Skip to content

Commit

Permalink
simplify the backtrace of include (#33256)
Browse files Browse the repository at this point in the history
Using the ability to delete functions, we can make this code a bit nicer and simpler.
(similar to #33087)
  • Loading branch information
vtjnash authored Sep 17, 2019
1 parent c40a93b commit 809d290
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 93 deletions.
103 changes: 57 additions & 46 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ baremodule Base

using Core.Intrinsics, Core.IR

# to start, we're going to use a very simple definition of `include`
# that doesn't require any function (except what we can get from the `Core` top-module)
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)

# from now on, this is now a top-module for resolving syntax
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)

Expand All @@ -20,50 +33,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)
Expand Down Expand Up @@ -279,7 +248,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
Expand Down Expand Up @@ -377,6 +360,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
Expand Down Expand Up @@ -405,7 +416,7 @@ function __init__()
nothing
end

INCLUDE_STATE = 3 # include = include_relative

end

const tot_time_stdlib = RefValue(0.0)
Expand Down
13 changes: 7 additions & 6 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -431,23 +431,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
Expand Down
25 changes: 1 addition & 24 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/jl_uv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ||
Expand Down
14 changes: 8 additions & 6 deletions src/rtutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ---------------------------------------------------------
Expand Down
6 changes: 0 additions & 6 deletions src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions test/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 809d290

Please sign in to comment.