@@ -1626,11 +1626,9 @@ function try_resolve_finalizer!(ir::IRCode, alloc_idx::Int, finalizer_idx::Int,
16261626 insert_bb != 0 || return nothing # verify post-dominator of all uses exists
16271627
16281628 # 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
16321629 finalizer_stmt = ir[SSAValue (finalizer_idx)][:stmt ]
16331630
1631+ current_task_ssa = nothing
16341632 if ! OptimizationParams (inlining. interp). assume_fatal_throw
16351633 # Collect all reachable blocks between the finalizer registration and the
16361634 # insertion point
@@ -1655,15 +1653,25 @@ function try_resolve_finalizer!(ir::IRCode, alloc_idx::Int, finalizer_idx::Int,
16551653
16561654 # An exception may be thrown between the finalizer registration and the point
16571655 # 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
16631667 end
16641668 end
16651669
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]
16671675 if length (finalizer_stmt. args) >= 4
16681676 inline = finalizer_stmt. args[4 ]
16691677 if inline === nothing
@@ -1681,8 +1689,16 @@ function try_resolve_finalizer!(ir::IRCode, alloc_idx::Int, finalizer_idx::Int,
16811689 newinst = add_flag (NewInstruction (Expr (:call , argexprs... ), Nothing), flag)
16821690 insert_node! (ir, loc, newinst, attach_after)
16831691 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=# true )
1698+ else
1699+ # Erase the call to `finalizer`
1700+ ir[SSAValue (finalizer_idx)][:stmt ] = nothing
1701+ end
16861702 return nothing
16871703end
16881704
0 commit comments