From c489d565677653df71daf47a238d52a7ae8385f9 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Tue, 6 Oct 2020 04:16:55 -0500 Subject: [PATCH 1/6] WIP: use invoke_in_world to shield Revise from self-invalidation --- src/legacy_loading.jl | 2 +- src/loading.jl | 2 +- src/packagedef.jl | 8 +++++++- src/pkgs.jl | 4 ++-- src/utils.jl | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/legacy_loading.jl b/src/legacy_loading.jl index e310f22f..5a6448f3 100644 --- a/src/legacy_loading.jl +++ b/src/legacy_loading.jl @@ -156,7 +156,7 @@ function parse_pkg_files(id::PkgId) # To reduce compiler latency, use runtime dispatch for `queue_includes!`. # `queue_includes!` requires compilation of the whole parsing/expression-splitting infrastructure, # and it's better to wait to compile it until we actually need it. - Base.invokelatest(queue_includes!, pkgdata, id) + Base.invoke_in_world(worldage[], queue_includes!, pkgdata, id) return pkgdata end diff --git a/src/loading.jl b/src/loading.jl index db8d0b22..07649851 100644 --- a/src/loading.jl +++ b/src/loading.jl @@ -48,7 +48,7 @@ function parse_pkg_files(id::PkgId) # To reduce compiler latency, use runtime dispatch for `queue_includes!`. # `queue_includes!` requires compilation of the whole parsing/expression-splitting infrastructure, # and it's better to wait to compile it until we actually need it. - Base.invokelatest(queue_includes!, pkgdata, id) + Base.invoke_in_world(worldage[], queue_includes!, pkgdata, id) return pkgdata end diff --git a/src/packagedef.jl b/src/packagedef.jl index 441c25ac..c053b8af 100644 --- a/src/packagedef.jl +++ b/src/packagedef.jl @@ -198,6 +198,11 @@ const silence_pkgs = Set{Symbol}() const depsdir = joinpath(dirname(@__DIR__), "deps") const silencefile = Ref(joinpath(depsdir, "silence.txt")) # Ref so that tests don't clobber +""" + world age +""" +const worldage = Ref{Union{Nothing,UInt}}(nothing) + ## ## The inputs are sets of expressions found in each file. ## Some of those expressions will generate methods which are identified via their signatures. @@ -1178,7 +1183,7 @@ end # This uses invokelatest not for reasons of world age but to ensure that the call is made at runtime. # This allows `revise_first` to be compiled without compiling `revise` itself, and greatly # reduces the overhead of using Revise. -revise_first(ex) = Expr(:toplevel, :(isempty($revision_queue) || Base.invokelatest($revise)), ex) +revise_first(ex) = Expr(:toplevel, :(isempty($revision_queue) || Base.invoke_in_world($(worldage[]), $revise)), ex) @noinline function run_backend(backend) while true @@ -1277,6 +1282,7 @@ function init_worker(p) end function __init__() + worldage[] = Base.get_world_counter() run_on_worker = get(ENV, "JULIA_REVISE_WORKER_ONLY", "0") if !(myid() == 1 || run_on_worker == "1") return nothing diff --git a/src/pkgs.jl b/src/pkgs.jl index 3b1cc929..7c7dd6a1 100644 --- a/src/pkgs.jl +++ b/src/pkgs.jl @@ -171,7 +171,7 @@ function maybe_add_includes_to_pkgdata!(pkgdata::PkgData, file::AbstractString, parse_source!(fi.modexsigs, fullfile, mod) if eval_now # Use runtime dispatch to reduce latency - Base.invokelatest(instantiate_sigs!, fi.modexsigs; mode=:eval) + Base.invoke_in_world(worldage[], instantiate_sigs!, fi.modexsigs; mode=:eval) end end # Add to watchlist @@ -237,7 +237,7 @@ function _add_require(sourcefile, modcaller, idmod, modname, expr) end end if complex - Base.invokelatest(eval_require_now, pkgdata, fileidx, filekey, sourcefile, modcaller, expr) + Base.invoke_in_world(worldage[], eval_require_now, pkgdata, fileidx, filekey, sourcefile, modcaller, expr) end finally unlock(requires_lock) diff --git a/src/utils.jl b/src/utils.jl index ec4aae51..49396899 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -193,7 +193,7 @@ This is used to make stacktraces obtained with Revise more similar to those obta without Revise, while retaining one entry to reveal Revise's involvement. """ function trim_toplevel!(bt) - # return bt # uncomment this line if you're debugging Revise itself + return bt n = itoplevel = length(bt) for (i, t) in enumerate(bt) sfs = StackTraces.lookup(t) From 51a768cd7be2feeea5b2fafcbe67d898218d98b5 Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Wed, 7 Oct 2020 14:27:17 +0200 Subject: [PATCH 2/6] use correct worldage in lowering and remotecall --- src/lowered.jl | 4 +++- src/packagedef.jl | 11 +++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/lowered.jl b/src/lowered.jl index e754c6bb..d3812e63 100644 --- a/src/lowered.jl +++ b/src/lowered.jl @@ -128,6 +128,8 @@ function methods_by_execution(mod::Module, ex::Expr; kwargs...) return methodinfo, docexprs, frame end +_lower(m::Module, ex, world::UInt) = ccall(:jl_expand_in_world, Any, (Any, Module, Cstring, Cint, Csize_t), ex, m, "none", 0, world) + """ methods_by_execution!(recurse=JuliaInterpreter.Compiled(), methodinfo, docexprs, mod::Module, ex::Expr; mode=:eval, disablebp=true, skip_include=mode!==:eval, always_rethrow=false) @@ -175,7 +177,7 @@ The other keyword arguments are more straightforward: function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, mod::Module, ex::Expr; mode::Symbol=:eval, disablebp::Bool=true, always_rethrow::Bool=false, kwargs...) mode ∈ (:sigs, :eval, :evalmeth, :evalassign) || error("unsupported mode ", mode) - lwr = Meta.lower(mod, ex) + lwr = _lower(mod, ex, worldage[]) isa(lwr, Expr) || return nothing, nothing if lwr.head === :error || lwr.head === :incomplete error("lowering returned an error, ", lwr) diff --git a/src/packagedef.jl b/src/packagedef.jl index c053b8af..0ed0b735 100644 --- a/src/packagedef.jl +++ b/src/packagedef.jl @@ -267,10 +267,13 @@ function delete_missing!(exs_sigs_old::ExprsSigs, exs_sigs_new) @debug "DeleteMethod" _group="Action" time=time() deltainfo=(sig, MethodSummary(m)) # Delete the corresponding methods for p in workers() - try # guard against serialization errors if the type isn't defined on the worker - remotecall(Core.eval, p, Main, :(delete_method_by_sig($sig))) - catch - end + #try # guard against serialization errors if the type isn't defined on the worker + future = remotecall(Core.eval, p, Main, :(delete_method_by_sig($sig))) + finalizer(future) do f + Base.invoke_in_world(worldage[], Distributed.finalize_ref, f) + end + #catch + #end end Base.delete_method(m) # Remove the entries from CodeTracking data From bd361c4172c8c92bb43a97b1e55ab491442bc1c8 Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Fri, 9 Oct 2020 14:54:45 +0200 Subject: [PATCH 3/6] make compatible with all Julia versions --- src/legacy_loading.jl | 2 +- src/loading.jl | 2 +- src/packagedef.jl | 24 +++++++++++++++++++++--- test/runtests.jl | 2 ++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/legacy_loading.jl b/src/legacy_loading.jl index 5a6448f3..e48e844e 100644 --- a/src/legacy_loading.jl +++ b/src/legacy_loading.jl @@ -156,7 +156,7 @@ function parse_pkg_files(id::PkgId) # To reduce compiler latency, use runtime dispatch for `queue_includes!`. # `queue_includes!` requires compilation of the whole parsing/expression-splitting infrastructure, # and it's better to wait to compile it until we actually need it. - Base.invoke_in_world(worldage[], queue_includes!, pkgdata, id) + invoke_revisefunc(worldage[], queue_includes!, pkgdata, id) return pkgdata end diff --git a/src/loading.jl b/src/loading.jl index 07649851..4dcd8072 100644 --- a/src/loading.jl +++ b/src/loading.jl @@ -48,7 +48,7 @@ function parse_pkg_files(id::PkgId) # To reduce compiler latency, use runtime dispatch for `queue_includes!`. # `queue_includes!` requires compilation of the whole parsing/expression-splitting infrastructure, # and it's better to wait to compile it until we actually need it. - Base.invoke_in_world(worldage[], queue_includes!, pkgdata, id) + invoke_revisefunc(worldage[], queue_includes!, pkgdata, id) return pkgdata end diff --git a/src/packagedef.jl b/src/packagedef.jl index 0ed0b735..23f93aef 100644 --- a/src/packagedef.jl +++ b/src/packagedef.jl @@ -199,7 +199,10 @@ const depsdir = joinpath(dirname(@__DIR__), "deps") const silencefile = Ref(joinpath(depsdir, "silence.txt")) # Ref so that tests don't clobber """ - world age + Revise.worldage + +The world age Revise was started in. Needed so that Revise doesn't delete methods +from under itself. """ const worldage = Ref{Union{Nothing,UInt}}(nothing) @@ -270,7 +273,7 @@ function delete_missing!(exs_sigs_old::ExprsSigs, exs_sigs_new) #try # guard against serialization errors if the type isn't defined on the worker future = remotecall(Core.eval, p, Main, :(delete_method_by_sig($sig))) finalizer(future) do f - Base.invoke_in_world(worldage[], Distributed.finalize_ref, f) + Base.invoke_revisefunc(worldage[], Distributed.finalize_ref, f) end #catch #end @@ -1182,11 +1185,26 @@ function maybe_set_prompt_color(color) return nothing end +if VERSION < v"1.6.0-DEV.1162" + const invoke_revisefunc = Base.invokelatest + const lower_in_reviseworld = Meta.lower +else + function invoke_revisefunc(f, args...; kwargs...) + return Base.invoke_in_world(worldage[], f, args...; kwargs...) + end + function lower_in_reviseworld(m::Module, @nospecialize(ex)) + return ccall(:jl_expand_in_world, Any, + (Any, Ref{Module}, Cstring, Cint, Csize_t), + ex, m, "none", 0, world, + ) + end +end + # On Julia 1.5.0-DEV.282 and higher, we can just use an AST transformation # This uses invokelatest not for reasons of world age but to ensure that the call is made at runtime. # This allows `revise_first` to be compiled without compiling `revise` itself, and greatly # reduces the overhead of using Revise. -revise_first(ex) = Expr(:toplevel, :(isempty($revision_queue) || Base.invoke_in_world($(worldage[]), $revise)), ex) +revise_first(ex) = Expr(:toplevel, :(isempty($revision_queue) || Base.invoke_revisefunc($revise)), ex) @noinline function run_backend(backend) while true diff --git a/test/runtests.jl b/test/runtests.jl index 0ac3bb9d..cf43d544 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,6 +4,8 @@ using Revise.CodeTracking using Revise.JuliaInterpreter using Test +@show VERSION + @test isempty(detect_ambiguities(Revise)) using Pkg, Unicode, Distributed, InteractiveUtils, REPL, UUIDs From ba5e6ca96e6b4094cab85a65ffcf7d92037288bf Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Sat, 10 Oct 2020 11:32:08 +0200 Subject: [PATCH 4/6] wip --- src/legacy_loading.jl | 3 ++- src/loading.jl | 3 ++- src/packagedef.jl | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/legacy_loading.jl b/src/legacy_loading.jl index e48e844e..e74b9bc2 100644 --- a/src/legacy_loading.jl +++ b/src/legacy_loading.jl @@ -156,7 +156,8 @@ function parse_pkg_files(id::PkgId) # To reduce compiler latency, use runtime dispatch for `queue_includes!`. # `queue_includes!` requires compilation of the whole parsing/expression-splitting infrastructure, # and it's better to wait to compile it until we actually need it. - invoke_revisefunc(worldage[], queue_includes!, pkgdata, id) + worldage[] = Base.get_world_counter() + invoke_revisefunc(queue_includes!, pkgdata, id) return pkgdata end diff --git a/src/loading.jl b/src/loading.jl index 4dcd8072..c2c44a14 100644 --- a/src/loading.jl +++ b/src/loading.jl @@ -48,7 +48,8 @@ function parse_pkg_files(id::PkgId) # To reduce compiler latency, use runtime dispatch for `queue_includes!`. # `queue_includes!` requires compilation of the whole parsing/expression-splitting infrastructure, # and it's better to wait to compile it until we actually need it. - invoke_revisefunc(worldage[], queue_includes!, pkgdata, id) + worldage[] = Base.get_world_counter() + invoke_revisefunc(queue_includes!, pkgdata, id) return pkgdata end diff --git a/src/packagedef.jl b/src/packagedef.jl index 23f93aef..792d4757 100644 --- a/src/packagedef.jl +++ b/src/packagedef.jl @@ -273,7 +273,7 @@ function delete_missing!(exs_sigs_old::ExprsSigs, exs_sigs_new) #try # guard against serialization errors if the type isn't defined on the worker future = remotecall(Core.eval, p, Main, :(delete_method_by_sig($sig))) finalizer(future) do f - Base.invoke_revisefunc(worldage[], Distributed.finalize_ref, f) + invoke_revisefunc(Distributed.finalize_ref, f) end #catch #end @@ -1204,7 +1204,7 @@ end # This uses invokelatest not for reasons of world age but to ensure that the call is made at runtime. # This allows `revise_first` to be compiled without compiling `revise` itself, and greatly # reduces the overhead of using Revise. -revise_first(ex) = Expr(:toplevel, :(isempty($revision_queue) || Base.invoke_revisefunc($revise)), ex) +revise_first(ex) = Expr(:toplevel, :(isempty($revision_queue) || (worldage[] = Base.get_world_counter(); invoke_revisefunc($revise))), ex) @noinline function run_backend(backend) while true @@ -1355,8 +1355,8 @@ function __init__() id = PkgId(nothing, "@REPL") pkgdatas[id] = pkgdata = PkgData(id, nothing) # Set the lookup callbacks - CodeTracking.method_lookup_callback[] = get_def - CodeTracking.expressions_callback[] = get_expressions + CodeTracking.method_lookup_callback[] = x -> (worldage[] = Base.get_world_counter(); invoke_revisefunc(get_def, x)) + CodeTracking.expressions_callback[] = x -> (worldage[] = Base.get_world_counter(); invoke_revisefunc(get_expressions, x)) # Watch the manifest file for changes mfile = manifest_file() From eb51a57f0c4221736fa36752599c3eb44327c572 Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Sat, 10 Oct 2020 23:55:57 +0200 Subject: [PATCH 5/6] foo --- Project.toml | 3 ++- src/packagedef.jl | 21 +++++++++++++-------- test/runtests.jl | 4 ++-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Project.toml b/Project.toml index 3a2cfb7a..b4c41bf9 100644 --- a/Project.toml +++ b/Project.toml @@ -29,6 +29,7 @@ Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" CRC32c = "8bf52ea8-c179-5cab-976a-9e18b702a9bc" CatIndices = "aafaddc9-749c-510e-ac4f-586e18779b91" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +Debugger = "31a5f54b-26ea-5ae9-a837-f05ce5417438" DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" EndpointRanges = "340492b5-2a47-5f55-813d-aca7ddf97656" EponymTuples = "97e2ac4a-e175-5f49-beb1-4d6866a6cdc3" @@ -57,4 +58,4 @@ SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "Base64", "CRC32c", "CatIndices", "Dates", "DelimitedFiles", "EndpointRanges", "EponymTuples", "Example", "Future", "IndirectArrays", "InteractiveUtils", "Libdl", "LinearAlgebra", "Logging", "MappedArrays", "Markdown", "Mmap", "Printf", "Profile", "Random", "Requires", "RoundingIntegers", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "SuiteSparse"] +test = ["Test", "Base64", "CRC32c", "CatIndices", "Dates", "DelimitedFiles", "EndpointRanges", "EponymTuples", "Example", "Future", "IndirectArrays", "InteractiveUtils", "Libdl", "LinearAlgebra", "Logging", "MappedArrays", "Markdown", "Mmap", "Printf", "Profile", "Random", "Requires", "RoundingIntegers", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "SuiteSparse", "Debugger"] diff --git a/src/packagedef.jl b/src/packagedef.jl index 792d4757..2c9e9c0e 100644 --- a/src/packagedef.jl +++ b/src/packagedef.jl @@ -198,13 +198,14 @@ const silence_pkgs = Set{Symbol}() const depsdir = joinpath(dirname(@__DIR__), "deps") const silencefile = Ref(joinpath(depsdir, "silence.txt")) # Ref so that tests don't clobber -""" - Revise.worldage - -The world age Revise was started in. Needed so that Revise doesn't delete methods -from under itself. -""" -const worldage = Ref{Union{Nothing,UInt}}(nothing) +#""" +# Revise.worldage +# +#The world age Revise was started in. Needed so that Revise doesn't delete methods +#from under itself. +#""" +#const worldage = Ref{Union{Nothing,UInt}}(nothing) +using CodeTracking: worldage ## ## The inputs are sets of expressions found in each file. @@ -1190,12 +1191,16 @@ if VERSION < v"1.6.0-DEV.1162" const lower_in_reviseworld = Meta.lower else function invoke_revisefunc(f, args...; kwargs...) + @show worldage[] + Base.show_backtrace(backtrace[1:2]) return Base.invoke_in_world(worldage[], f, args...; kwargs...) end function lower_in_reviseworld(m::Module, @nospecialize(ex)) + @show worldage[] + Base.show_backtrace(backtrace[1:2]) return ccall(:jl_expand_in_world, Any, (Any, Ref{Module}, Cstring, Cint, Csize_t), - ex, m, "none", 0, world, + ex, m, "none", 0, worldage[], ) end end diff --git a/test/runtests.jl b/test/runtests.jl index cf43d544..0ff759c9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -473,8 +473,8 @@ end @eval @test $(fn4)() == 4 @eval @test $(fn5)() == 5 @eval @test $(fn6)() == 6 - m = @eval first(methods($fn1)) - rex = Revise.RelocatableExpr(definition(m)) + m = @show @eval first(methods($fn1)) + rex = Revise.RelocatableExpr(@show definition(m)) @test rex == Revise.RelocatableExpr(:( $fn1() = 1 )) # Check that definition returns copies rex2 = deepcopy(rex) From 210c22080f8d2da32b5ae44865a39b5f15ec4eb8 Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Sun, 11 Oct 2020 13:13:04 +0200 Subject: [PATCH 6/6] wip --- Project.toml | 3 +-- src/legacy_loading.jl | 2 +- src/loading.jl | 1 - src/lowered.jl | 2 +- src/packagedef.jl | 35 ++++++++++++++++++++++------------- src/pkgs.jl | 6 ++++-- test/runtests.jl | 6 ++---- 7 files changed, 31 insertions(+), 24 deletions(-) diff --git a/Project.toml b/Project.toml index b4c41bf9..3a2cfb7a 100644 --- a/Project.toml +++ b/Project.toml @@ -29,7 +29,6 @@ Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" CRC32c = "8bf52ea8-c179-5cab-976a-9e18b702a9bc" CatIndices = "aafaddc9-749c-510e-ac4f-586e18779b91" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -Debugger = "31a5f54b-26ea-5ae9-a837-f05ce5417438" DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" EndpointRanges = "340492b5-2a47-5f55-813d-aca7ddf97656" EponymTuples = "97e2ac4a-e175-5f49-beb1-4d6866a6cdc3" @@ -58,4 +57,4 @@ SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "Base64", "CRC32c", "CatIndices", "Dates", "DelimitedFiles", "EndpointRanges", "EponymTuples", "Example", "Future", "IndirectArrays", "InteractiveUtils", "Libdl", "LinearAlgebra", "Logging", "MappedArrays", "Markdown", "Mmap", "Printf", "Profile", "Random", "Requires", "RoundingIntegers", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "SuiteSparse", "Debugger"] +test = ["Test", "Base64", "CRC32c", "CatIndices", "Dates", "DelimitedFiles", "EndpointRanges", "EponymTuples", "Example", "Future", "IndirectArrays", "InteractiveUtils", "Libdl", "LinearAlgebra", "Logging", "MappedArrays", "Markdown", "Mmap", "Printf", "Profile", "Random", "Requires", "RoundingIntegers", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "SuiteSparse"] diff --git a/src/legacy_loading.jl b/src/legacy_loading.jl index e74b9bc2..725f3496 100644 --- a/src/legacy_loading.jl +++ b/src/legacy_loading.jl @@ -156,7 +156,7 @@ function parse_pkg_files(id::PkgId) # To reduce compiler latency, use runtime dispatch for `queue_includes!`. # `queue_includes!` requires compilation of the whole parsing/expression-splitting infrastructure, # and it's better to wait to compile it until we actually need it. - worldage[] = Base.get_world_counter() + #worldage[] = Base.get_world_counter() invoke_revisefunc(queue_includes!, pkgdata, id) return pkgdata end diff --git a/src/loading.jl b/src/loading.jl index c2c44a14..79b7b7d7 100644 --- a/src/loading.jl +++ b/src/loading.jl @@ -48,7 +48,6 @@ function parse_pkg_files(id::PkgId) # To reduce compiler latency, use runtime dispatch for `queue_includes!`. # `queue_includes!` requires compilation of the whole parsing/expression-splitting infrastructure, # and it's better to wait to compile it until we actually need it. - worldage[] = Base.get_world_counter() invoke_revisefunc(queue_includes!, pkgdata, id) return pkgdata end diff --git a/src/lowered.jl b/src/lowered.jl index d3812e63..bbc65010 100644 --- a/src/lowered.jl +++ b/src/lowered.jl @@ -177,7 +177,7 @@ The other keyword arguments are more straightforward: function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, mod::Module, ex::Expr; mode::Symbol=:eval, disablebp::Bool=true, always_rethrow::Bool=false, kwargs...) mode ∈ (:sigs, :eval, :evalmeth, :evalassign) || error("unsupported mode ", mode) - lwr = _lower(mod, ex, worldage[]) + lwr = lower_in_reviseworld(mod, ex) isa(lwr, Expr) || return nothing, nothing if lwr.head === :error || lwr.head === :incomplete error("lowering returned an error, ", lwr) diff --git a/src/packagedef.jl b/src/packagedef.jl index 2c9e9c0e..8526b067 100644 --- a/src/packagedef.jl +++ b/src/packagedef.jl @@ -198,14 +198,14 @@ const silence_pkgs = Set{Symbol}() const depsdir = joinpath(dirname(@__DIR__), "deps") const silencefile = Ref(joinpath(depsdir, "silence.txt")) # Ref so that tests don't clobber -#""" -# Revise.worldage -# -#The world age Revise was started in. Needed so that Revise doesn't delete methods -#from under itself. -#""" -#const worldage = Ref{Union{Nothing,UInt}}(nothing) -using CodeTracking: worldage +""" + Revise.worldage + +The world age Revise was started in. Needed so that Revise doesn't delete methods +from under itself. +""" +const worldage = Ref{Union{Nothing,UInt}}(nothing) +#using CodeTracking: worldage ## ## The inputs are sets of expressions found in each file. @@ -639,6 +639,7 @@ function handle_deletions(pkgdata, file) topmod = first(keys(mexsold)) fileok = file_exists(filep) mexsnew = fileok ? parse_source(filep, topmod) : ModuleExprsSigs(topmod) + worldage[] = Base.get_world_counter() if mexsnew !== nothing delete_missing!(mexsold, mexsnew) end @@ -732,6 +733,7 @@ function revise(; throw=false) # Do all the deletion first. This ensures that a method that moved from one file to another # won't get redefined first and deleted second. + @show worldage[] = Base.get_world_counter() revision_errors = [] queue = sort!(collect(revision_queue); lt=pkgfileless) finished = eltype(revision_queue)[] @@ -764,6 +766,7 @@ function revise(; throw=false) mode ∈ (:sigs, :eval, :evalmeth, :evalassign) || error("unsupported mode ", mode) exsold = get(fi.modexsigs, mod, empty_exs_sigs) for rex in keys(exsnew) + @show Base.get_world_counter() sigs, includes = eval_rex(rex, exsold, mod; mode=mode) if sigs !== nothing exsnew[rex] = sigs @@ -1191,13 +1194,17 @@ if VERSION < v"1.6.0-DEV.1162" const lower_in_reviseworld = Meta.lower else function invoke_revisefunc(f, args...; kwargs...) - @show worldage[] - Base.show_backtrace(backtrace[1:2]) + #@show worldage[] + #@show Base.get_world_counter() + #Base.show_backtrace(stdout, backtrace()[1:4]) + #println() return Base.invoke_in_world(worldage[], f, args...; kwargs...) end function lower_in_reviseworld(m::Module, @nospecialize(ex)) - @show worldage[] - Base.show_backtrace(backtrace[1:2]) + #@show worldage[] + #@show Base.get_world_counter() + #Base.show_backtrace(stdout, backtrace()[1:1]) + #println() return ccall(:jl_expand_in_world, Any, (Any, Ref{Module}, Cstring, Cint, Csize_t), ex, m, "none", 0, worldage[], @@ -1209,7 +1216,7 @@ end # This uses invokelatest not for reasons of world age but to ensure that the call is made at runtime. # This allows `revise_first` to be compiled without compiling `revise` itself, and greatly # reduces the overhead of using Revise. -revise_first(ex) = Expr(:toplevel, :(isempty($revision_queue) || (worldage[] = Base.get_world_counter(); invoke_revisefunc($revise))), ex) +revise_first(ex) = Expr(:toplevel, :(isempty($revision_queue) || (#=worldage[] = Base.get_world_counter(); =#invoke_revisefunc($revise))), ex) @noinline function run_backend(backend) while true @@ -1362,6 +1369,8 @@ function __init__() # Set the lookup callbacks CodeTracking.method_lookup_callback[] = x -> (worldage[] = Base.get_world_counter(); invoke_revisefunc(get_def, x)) CodeTracking.expressions_callback[] = x -> (worldage[] = Base.get_world_counter(); invoke_revisefunc(get_expressions, x)) + CodeTracking.method_lookup_callback[] = get_def + CodeTracking.expressions_callback[] = get_expressions # Watch the manifest file for changes mfile = manifest_file() diff --git a/src/pkgs.jl b/src/pkgs.jl index 7c7dd6a1..15df6157 100644 --- a/src/pkgs.jl +++ b/src/pkgs.jl @@ -171,7 +171,8 @@ function maybe_add_includes_to_pkgdata!(pkgdata::PkgData, file::AbstractString, parse_source!(fi.modexsigs, fullfile, mod) if eval_now # Use runtime dispatch to reduce latency - Base.invoke_in_world(worldage[], instantiate_sigs!, fi.modexsigs; mode=:eval) + #Base.invoke_in_world(worldage[], instantiate_sigs!, fi.modexsigs; mode=:eval) + Base.invokelatest(instantiate_sigs!, fi.modexsigs; mode=:eval) end end # Add to watchlist @@ -237,7 +238,8 @@ function _add_require(sourcefile, modcaller, idmod, modname, expr) end end if complex - Base.invoke_in_world(worldage[], eval_require_now, pkgdata, fileidx, filekey, sourcefile, modcaller, expr) + #Base.invoke_in_world(worldage[], eval_require_now, pkgdata, fileidx, filekey, sourcefile, modcaller, expr) + Base.invokelatest(eval_require_now, pkgdata, fileidx, filekey, sourcefile, modcaller, expr) end finally unlock(requires_lock) diff --git a/test/runtests.jl b/test/runtests.jl index 0ff759c9..0ac3bb9d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,8 +4,6 @@ using Revise.CodeTracking using Revise.JuliaInterpreter using Test -@show VERSION - @test isempty(detect_ambiguities(Revise)) using Pkg, Unicode, Distributed, InteractiveUtils, REPL, UUIDs @@ -473,8 +471,8 @@ end @eval @test $(fn4)() == 4 @eval @test $(fn5)() == 5 @eval @test $(fn6)() == 6 - m = @show @eval first(methods($fn1)) - rex = Revise.RelocatableExpr(@show definition(m)) + m = @eval first(methods($fn1)) + rex = Revise.RelocatableExpr(definition(m)) @test rex == Revise.RelocatableExpr(:( $fn1() = 1 )) # Check that definition returns copies rex2 = deepcopy(rex)