Skip to content

Commit

Permalink
simplify the backtrace of include
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 committed Sep 13, 2019
1 parent 51b3227 commit 19d5ae2
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 @@ -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
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 19d5ae2

Please sign in to comment.