diff --git a/NEWS.md b/NEWS.md index b1442f0192350d..f908da52b06f73 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,6 +16,9 @@ New language features Language changes ---------------- +* Newly created Task objects (`@spawn`, `@async`, etc.) now adopt the world-age for methods from their parent + Task upon creation, instead of using the global latest world at start. This is done to enable inference to + eventually optimize these calls. Places that wish for the old behavior may use `Base.invokelatest`. ([#41449]) Compiler/Runtime improvements ----------------------------- diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index e7ae0123117b5f..945a7a05674686 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -1533,8 +1533,9 @@ DomainError """ Task(func) -Create a `Task` (i.e. coroutine) to execute the given function `func` (which must be -callable with no arguments). The task exits when this function returns. +Create a `Task` (i.e. coroutine) to execute the given function `func` (which +must be callable with no arguments). The task exits when this function returns. +The task will run in the "world age" from the parent at construction when [`schedule`](@ref)d. # Examples ```jldoctest diff --git a/src/task.c b/src/task.c index f72e910f871de0..52cd2dfc5bcbae 100644 --- a/src/task.c +++ b/src/task.c @@ -754,7 +754,7 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion t->prio = -1; jl_atomic_store_relaxed(&t->tid, t->copy_stack ? ct->tid : -1); // copy_stacks are always pinned since they can't be moved t->ptls = NULL; - t->world_age = 0; + t->world_age = ct->world_age; #ifdef COPY_STACKS if (!t->copy_stack) { @@ -880,7 +880,6 @@ CFI_NORETURN jl_sigint_safepoint(ptls); } JL_TIMING(ROOT); - ct->world_age = jl_world_counter; res = jl_apply(&ct->start, 1); } JL_CATCH { diff --git a/stdlib/Distributed/src/process_messages.jl b/stdlib/Distributed/src/process_messages.jl index 732b972858dc97..a093ffff01d347 100644 --- a/stdlib/Distributed/src/process_messages.jl +++ b/stdlib/Distributed/src/process_messages.jl @@ -57,7 +57,7 @@ function showerror(io::IO, re::RemoteException) showerror(io, re.captured) end -function run_work_thunk(thunk, print_error) +function run_work_thunk(thunk::Function, print_error::Bool) local result try result = thunk() @@ -271,11 +271,11 @@ function process_hdr(s, validate_cookie) end function handle_msg(msg::CallMsg{:call}, header, r_stream, w_stream, version) - schedule_call(header.response_oid, ()->msg.f(msg.args...; msg.kwargs...)) + schedule_call(header.response_oid, ()->invokelatest(msg.f, msg.args...; msg.kwargs...)) end function handle_msg(msg::CallMsg{:call_fetch}, header, r_stream, w_stream, version) errormonitor(@async begin - v = run_work_thunk(()->msg.f(msg.args...; msg.kwargs...), false) + v = run_work_thunk(()->invokelatest(msg.f, msg.args...; msg.kwargs...), false) if isa(v, SyncTake) try deliver_result(w_stream, :call_fetch, header.notify_oid, v.v) @@ -291,14 +291,14 @@ end function handle_msg(msg::CallWaitMsg, header, r_stream, w_stream, version) errormonitor(@async begin - rv = schedule_call(header.response_oid, ()->msg.f(msg.args...; msg.kwargs...)) + rv = schedule_call(header.response_oid, ()->invokelatest(msg.f, msg.args...; msg.kwargs...)) deliver_result(w_stream, :call_wait, header.notify_oid, fetch(rv.c)) nothing end) end function handle_msg(msg::RemoteDoMsg, header, r_stream, w_stream, version) - errormonitor(@async run_work_thunk(()->msg.f(msg.args...; msg.kwargs...), true)) + errormonitor(@async run_work_thunk(()->invokelatest(msg.f, msg.args...; msg.kwargs...), true)) end function handle_msg(msg::ResultMsg, header, r_stream, w_stream, version) diff --git a/stdlib/Distributed/src/remotecall.jl b/stdlib/Distributed/src/remotecall.jl index fabcf106860688..f3875e8ee05fc6 100644 --- a/stdlib/Distributed/src/remotecall.jl +++ b/stdlib/Distributed/src/remotecall.jl @@ -370,10 +370,7 @@ end # make a thunk to call f on args in a way that simulates what would happen if # the function were sent elsewhere function local_remotecall_thunk(f, args, kwargs) - if isempty(args) && isempty(kwargs) - return f - end - return ()->f(args...; kwargs...) + return ()->invokelatest(f, args...; kwargs...) end function remotecall(f, w::LocalProcess, args...; kwargs...) diff --git a/test/worlds.jl b/test/worlds.jl index 2b4f575e1905ae..c8d671bea63d81 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -107,8 +107,24 @@ end g265() = [f265(x) for x in 1:3.] wc265 = get_world_counter() -f265(::Any) = 1.0 -@test wc265 + 1 == get_world_counter() +wc265_41332a = Task(tls_world_age) +@test tls_world_age() == wc265 +(function () + global wc265_41332b = Task(tls_world_age) + @eval f265(::Any) = 1.0 + global wc265_41332c = Base.invokelatest(Task, tls_world_age) + global wc265_41332d = Task(tls_world_age) + nothing +end)() +@test wc265 + 2 == get_world_counter() == tls_world_age() +schedule(wc265_41332a) +schedule(wc265_41332b) +schedule(wc265_41332c) +schedule(wc265_41332d) +@test wc265 == fetch(wc265_41332a) +@test wc265 + 1 == fetch(wc265_41332b) +@test wc265 + 2 == fetch(wc265_41332c) +@test wc265 + 1 == fetch(wc265_41332d) chnls, tasks = Base.channeled_tasks(2, wfunc) t265 = tasks[1]