From cc7533fae53691af5363fd1311bd8c7d73923f5e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 13 Sep 2019 15:44:22 -0400 Subject: [PATCH] simplify the backtrace of include Using the ability to delete functions, we can make this code a bit nicer and simpler. (similar to #33087) --- base/Base.jl | 100 ++++++++++++++++++++++++--------------------- base/client.jl | 13 +++--- base/loading.jl | 25 +----------- src/jl_uv.c | 2 +- src/rtutils.c | 14 ++++--- src/toplevel.c | 6 --- test/precompile.jl | 8 ++-- 7 files changed, 75 insertions(+), 93 deletions(-) diff --git a/base/Base.jl b/base/Base.jl index f64c061f9e9fb..04e21b7532af8 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -4,6 +4,16 @@ baremodule Base using Core.Intrinsics, Core.IR +const _included_files = Array{Tuple{Module,String},1}() +function include(mod::Module, path::String) + ccall(:jl_array_grow_end, Cvoid, (Any, UInt), _included_files, UInt(1)) + Core.arrayset(true, _included_files, (mod, ccall(:jl_prepend_cwd, Any, (Any,), path)), arraylen(_included_files)) + Core.println(path) + ccall(:jl_uv_flush, Nothing, (Ptr{Nothing},), Core.io_pointer(Core.stdout)) + Core.include(mod, path) +end +include(path::String) = include(Base, path) + const is_primary_base_module = ccall(:jl_module_parent, Ref{Module}, (Any,), Base) === Core.Main ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Base, is_primary_base_module) @@ -20,50 +30,6 @@ setproperty!(x::Tuple, f::Int, v) = setfield!(x, f, v) # to get a decent error getproperty(Core.@nospecialize(x), f::Symbol) = getfield(x, f) setproperty!(x, f::Symbol, v) = setfield!(x, f, convert(fieldtype(typeof(x), f), v)) -function include_relative end -function include(mod::Module, path::AbstractString) - local result - if INCLUDE_STATE === 1 - result = _include1(mod, path) - elseif INCLUDE_STATE === 2 - result = _include(mod, path) - elseif INCLUDE_STATE === 3 - result = include_relative(mod, path) - end - result -end -function include(path::AbstractString) - local result - if INCLUDE_STATE === 1 - result = _include1(Base, path) - elseif INCLUDE_STATE === 2 - result = _include(Base, path) - else - # to help users avoid error (accidentally evaluating into Base), this is not allowed - error("Base.include(string) is discontinued, use `include(fname)` or `Base.include(@__MODULE__, fname)` instead.") - end - result -end -const _included_files = Array{Tuple{Module,String},1}() -function _include1(mod::Module, path) - Core.Compiler.push!(_included_files, (mod, ccall(:jl_prepend_cwd, Any, (Any,), path))) - Core.include(mod, path) -end -let SOURCE_PATH = "" - # simple, race-y TLS, relative include - global _include - function _include(mod::Module, path) - prev = SOURCE_PATH - path = normpath(joinpath(dirname(prev), path)) - push!(_included_files, (mod, abspath(path))) - SOURCE_PATH = path - result = Core.include(mod, path) - SOURCE_PATH = prev - result - end -end -INCLUDE_STATE = 1 # include = Core.include - include("coreio.jl") eval(x) = Core.eval(Base, x) @@ -279,7 +245,21 @@ using .Math const (√)=sqrt const (∛)=cbrt -INCLUDE_STATE = 2 # include = _include (from lines above) +# now switch to a simple, race-y TLS, relative include for the rest of Base +delete_method(which(include, (Module, String))) +let SOURCE_PATH = "" + global function include(mod::Module, path::String) + prev = SOURCE_PATH + path = normpath(joinpath(dirname(prev), path)) + Core.println(path) + ccall(:jl_uv_flush, Nothing, (Ptr{Nothing},), Core.io_pointer(Core.stdout)) + push!(_included_files, (mod, abspath(path))) + SOURCE_PATH = path + result = Core.include(mod, path) + SOURCE_PATH = prev + return result + end +end # reduction along dims include("reducedim.jl") # macros in this file relies on string.jl @@ -377,6 +357,34 @@ if isdefined(Core, :Compiler) && is_primary_base_module Docs.loaddocs(Core.Compiler.CoreDocs.DOCS) end +# finally, now make `include` point to the full version +for m in methods(include) + delete_method(m) +end +# These functions are duplicated in client.jl/include(::String) for +# nicer stacktraces. Modifications here have to be backported there +include(mod::Module, path::AbstractString) = include(mod, convert(String, path)) +function include(mod::Module, _path::String) + path, prev = _include_dependency(mod, _path) + for callback in include_callbacks # to preserve order, must come before Core.include + invokelatest(callback, mod, path) + end + tls = task_local_storage() + tls[:SOURCE_PATH] = path + local result + try + # result = Core.include(mod, path) + result = ccall(:jl_load_, Any, (Any, Any), mod, path) + finally + if prev === nothing + delete!(tls, :SOURCE_PATH) + else + tls[:SOURCE_PATH] = prev + end + end + return result +end + end_base_include = time_ns() if is_primary_base_module @@ -405,7 +413,7 @@ function __init__() nothing end -INCLUDE_STATE = 3 # include = include_relative + end const tot_time_stdlib = RefValue(0.0) diff --git a/base/client.jl b/base/client.jl index a9377b5b920a9..2cf0dc2a7c0fb 100644 --- a/base/client.jl +++ b/base/client.jl @@ -429,23 +429,24 @@ end # MainInclude exists to hide Main.include and eval from `names(Main)`. baremodule MainInclude +using ..Base # We inline the definition of include from loading.jl/include_relative to get one-frame stacktraces. # include(fname::AbstractString) = Main.Base.include(Main, fname) function include(fname::AbstractString) mod = Main - isa(fname, String) || (fname = String(fname)) - path, prev = Main.Base._include_dependency(mod, fname) - for callback in Main.Base.include_callbacks # to preserve order, must come before Core.include - Main.Base.invokelatest(callback, mod, path) + isa(fname, String) || (fname = Base.convert(String, fname)) + path, prev = Base._include_dependency(mod, fname) + for callback in Base.include_callbacks # to preserve order, must come before Core.include + Base.invokelatest(callback, mod, path) end - tls = Main.Base.task_local_storage() + tls = Base.task_local_storage() tls[:SOURCE_PATH] = path local result try result = ccall(:jl_load_, Any, (Any, Any), mod, path) finally if prev === nothing - Main.Base.delete!(tls, :SOURCE_PATH) + Base.delete!(tls, :SOURCE_PATH) else tls[:SOURCE_PATH] = prev end diff --git a/base/loading.jl b/base/loading.jl index 45963a1c1294c..430a1c6e53f92 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1050,7 +1050,7 @@ function _require(pkg::PkgId) ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), __toplevel__, uuid) end try - include_relative(__toplevel__, path) + include(__toplevel__, path) return finally if uuid !== old_uuid @@ -1092,29 +1092,6 @@ function source_dir() return p === nothing ? pwd() : dirname(p) end -# These functions are duplicated in client.jl/include(::String) for -# nicer stacktraces. Modifications here have to be backported there -include_relative(mod::Module, path::AbstractString) = include_relative(mod, String(path)) -function include_relative(mod::Module, _path::String) - path, prev = _include_dependency(mod, _path) - for callback in include_callbacks # to preserve order, must come before Core.include - invokelatest(callback, mod, path) - end - tls = task_local_storage() - tls[:SOURCE_PATH] = path - local result - try - result = Core.include(mod, path) - finally - if prev === nothing - delete!(tls, :SOURCE_PATH) - else - tls[:SOURCE_PATH] = prev - end - end - return result -end - """ Base.include([m::Module,] path::AbstractString) diff --git a/src/jl_uv.c b/src/jl_uv.c index ba86352488e51..b2b464779fb22 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -157,7 +157,7 @@ static void uv_flush_callback(uv_write_t *req, int status) // Turn a normal write into a blocking write (primarily for use from C and gdb). // Warning: This calls uv_run, so it can have unbounded side-effects. // Be care where you call it from! - the libuv loop is also not reentrant. -void jl_uv_flush(uv_stream_t *stream) +JL_DLLEXPORT void jl_uv_flush(uv_stream_t *stream) { if (stream == (void*)STDIN_FILENO || stream == (void*)STDOUT_FILENO || diff --git a/src/rtutils.c b/src/rtutils.c index 4be34d20fe315..ed7af01fd7520 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -496,16 +496,18 @@ JL_DLLEXPORT void jl_flush_cstdio(void) JL_NOTSAFEPOINT JL_DLLEXPORT jl_value_t *jl_stdout_obj(void) JL_NOTSAFEPOINT { - if (jl_base_module == NULL) return NULL; - jl_value_t *stdout_obj = jl_get_module_binding(jl_base_module, jl_symbol("stdout"))->value; - return stdout_obj; + if (jl_base_module == NULL) + return NULL; + jl_binding_t *stdout_obj = jl_get_module_binding(jl_base_module, jl_symbol("stdout")); + return stdout_obj ? stdout_obj->value : NULL; } JL_DLLEXPORT jl_value_t *jl_stderr_obj(void) JL_NOTSAFEPOINT { - if (jl_base_module == NULL) return NULL; - jl_value_t *stderr_obj = jl_get_module_binding(jl_base_module, jl_symbol("stderr"))->value; - return stderr_obj; + if (jl_base_module == NULL) + return NULL; + jl_binding_t *stderr_obj = jl_get_module_binding(jl_base_module, jl_symbol("stderr")); + return stderr_obj ? stderr_obj->value : NULL; } // toys for debugging --------------------------------------------------------- diff --git a/src/toplevel.c b/src/toplevel.c index a32ed46e41991..a22f966559991 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -865,12 +865,6 @@ JL_DLLEXPORT jl_value_t *jl_infer_thunk(jl_code_info_t *thk, jl_module_t *m) JL_DLLEXPORT jl_value_t *jl_load(jl_module_t *module, const char *fname) { - if (module->istopmod) { - jl_printf(JL_STDOUT, "%s\r\n", fname); -#ifdef _OS_WINDOWS_ - jl_uv_flush(JL_STDOUT); -#endif - } uv_stat_t stbuf; if (jl_stat(fname, (char*)&stbuf) != 0 || (stbuf.st_mode & S_IFMT) != S_IFREG) { jl_errorf("could not open file %s", fname); diff --git a/test/precompile.jl b/test/precompile.jl index 7ee30ee2006c8..9f7e4f04c59cd 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -144,11 +144,11 @@ try missing, missing, missing, missing, missing, 6] - let some_method = which(Base.include, (String,)) + let some_method = which(Base.include, (Module, String,)) # global const some_method // FIXME: support for serializing a direct reference to an external Method not implemented global const some_linfo = ccall(:jl_specializations_get_linfo, Ref{Core.MethodInstance}, (Any, Any, Any, UInt), - some_method, Tuple{typeof(Base.include), String}, Core.svec(), typemax(UInt)) + some_method, Tuple{typeof(Base.include), Module, String}, Core.svec(), typemax(UInt)) end g() = override(1.0) @@ -287,10 +287,10 @@ try Val{3}, Val{nothing}}, 0:25) - some_method = which(Base.include, (String,)) + some_method = which(Base.include, (Module, String,)) some_linfo = ccall(:jl_specializations_get_linfo, Ref{Core.MethodInstance}, (Any, Any, Any, UInt), - some_method, Tuple{typeof(Base.include), String}, Core.svec(), typemax(UInt)) + some_method, Tuple{typeof(Base.include), Module, String}, Core.svec(), typemax(UInt)) @test Foo.some_linfo::Core.MethodInstance === some_linfo ft = Base.datatype_fieldtypes