@@ -1626,11 +1626,9 @@ function try_resolve_finalizer!(ir::IRCode, alloc_idx::Int, finalizer_idx::Int,
1626
1626
insert_bb != 0 || return nothing # verify post-dominator of all uses exists
1627
1627
1628
1628
# Figure out the exact statement where we're going to inline the finalizer.
1629
- loc = insert_idx === nothing ? first (ir. cfg. blocks[insert_bb]. stmts) : insert_idx:: Int
1630
- attach_after = insert_idx != = nothing
1631
- flag = info isa FinalizerInfo ? flags_for_effects (info. effects) : IR_FLAG_NULL
1632
1629
finalizer_stmt = ir[SSAValue (finalizer_idx)][:stmt ]
1633
1630
1631
+ current_task_ssa = nothing
1634
1632
if ! OptimizationParams (inlining. interp). assume_fatal_throw
1635
1633
# Collect all reachable blocks between the finalizer registration and the
1636
1634
# insertion point
@@ -1655,15 +1653,25 @@ function try_resolve_finalizer!(ir::IRCode, alloc_idx::Int, finalizer_idx::Int,
1655
1653
1656
1654
# An exception may be thrown between the finalizer registration and the point
1657
1655
# where the object’s lifetime ends (`insert_idx`): In such cases, we can’t
1658
- # remove the finalizer registration, but we can still insert a `Core.finalize`
1659
- # call at `insert_idx` while leaving the registration intact.
1660
- newinst = add_flag (NewInstruction (Expr (:call , GlobalRef (Core, :finalize ), finalizer_stmt. args[3 ]), Nothing), flag)
1661
- insert_node! (ir, loc, newinst, attach_after)
1662
- return nothing
1656
+ # remove the finalizer registration, but we can still inline the finalizer
1657
+ # with inserting `Core._cancel_finalizer` at the end.
1658
+ # Here, prepare a reference to the current task object that should be passed to
1659
+ # `Core._cancel_finalizer` and insert it into `Core.finalizer` so that the
1660
+ # finalizer is added to the ptls of the current task.
1661
+ current_task_stmt = Expr (:foreigncall , QuoteNode (:jl_get_current_task ),
1662
+ Core. Ref{Core. Task}, Core. svec (), 0 , QuoteNode (:ccall ))
1663
+ newinst = NewInstruction (current_task_stmt, Core. Task)
1664
+ current_task_ssa = insert_node! (ir, finalizer_idx, newinst)
1665
+ push! (finalizer_stmt. args, current_task_ssa)
1666
+ break
1663
1667
end
1664
1668
end
1665
1669
1666
- argexprs = Any[finalizer_stmt. args[2 ], finalizer_stmt. args[3 ]]
1670
+ loc = insert_idx === nothing ? first (ir. cfg. blocks[insert_bb]. stmts) : insert_idx:: Int
1671
+ attach_after = insert_idx != = nothing
1672
+ flag = info isa FinalizerInfo ? flags_for_effects (info. effects) : IR_FLAG_NULL
1673
+ alloc_obj = finalizer_stmt. args[3 ]
1674
+ argexprs = Any[finalizer_stmt. args[2 ], alloc_obj]
1667
1675
if length (finalizer_stmt. args) >= 4
1668
1676
inline = finalizer_stmt. args[4 ]
1669
1677
if inline === nothing
@@ -1681,8 +1689,16 @@ function try_resolve_finalizer!(ir::IRCode, alloc_idx::Int, finalizer_idx::Int,
1681
1689
newinst = add_flag (NewInstruction (Expr (:call , argexprs... ), Nothing), flag)
1682
1690
insert_node! (ir, loc, newinst, attach_after)
1683
1691
end
1684
- # Erase the call to `finalizer`
1685
- ir[SSAValue (finalizer_idx)][:stmt ] = nothing
1692
+ cancel_registration = current_task_ssa != = nothing
1693
+ if cancel_registration
1694
+ lookup_idx_ssa = SSAValue (finalizer_idx)
1695
+ finalize_call = Expr (:call , GlobalRef (Core, :_cancel_finalizer ), alloc_obj, current_task_ssa, lookup_idx_ssa)
1696
+ newinst = add_flag (NewInstruction (finalize_call, Nothing), flag)
1697
+ insert_node! (ir, loc, newinst, attach_after)
1698
+ else
1699
+ # Erase the call to `finalizer`
1700
+ ir[SSAValue (finalizer_idx)][:stmt ] = nothing
1701
+ end
1686
1702
return nothing
1687
1703
end
1688
1704
0 commit comments