Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 2 additions & 25 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -365,31 +365,8 @@ for m in methods(include)
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(identity, mod, _path)
function include(mapexpr::Function, mod::Module, _path::AbstractString)
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)
if mapexpr === identity
result = ccall(:jl_load, Any, (Any, Cstring), mod, path)
else
result = ccall(:jl_load_rewrite, Any, (Any, Cstring, Any), mod, path, mapexpr)
end
finally
if prev === nothing
delete!(tls, :SOURCE_PATH)
else
tls[:SOURCE_PATH] = prev
end
end
return result
end
include(mod::Module, _path::AbstractString) = _include(identity, mod, _path)
include(mapexpr::Function, mod::Module, _path::AbstractString) = _include(mapexpr, mod, _path)

end_base_include = time_ns()

Expand Down
26 changes: 4 additions & 22 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -423,30 +423,12 @@ end
# MainInclude exists to hide Main.include and eval from `names(Main)`.
baremodule MainInclude
using ..Base
include(mapexpr::Function, fname::AbstractString) = Base.include(mapexpr, Main, fname)
# We inline the definition of include from loading.jl/include_relative to get one-frame stacktraces
# for the common case of include(fname). Otherwise we would use:
# include(fname::AbstractString) = Base.include(Main, fname)
# These definitions calls Base._include rather than Base.include to get
# one-frame stacktraces for the common case of using include(fname) in Main.
include(mapexpr::Function, fname::AbstractString) = Base._include(mapexpr, Main, fname)
function include(fname::AbstractString)
mod = Main
isa(fname, String) || (fname = Base.convert(String, fname)::String)
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 = Base.task_local_storage()
tls[:SOURCE_PATH] = path
local result
try
result = ccall(:jl_load, Any, (Any, Cstring), mod, path)
finally
if prev === nothing
Base.delete!(tls, :SOURCE_PATH)
else
tls[:SOURCE_PATH] = prev
end
end
return result
Base._include(identity, Main, fname)
end
eval(x) = Core.eval(Main, x)
end
Expand Down
13 changes: 10 additions & 3 deletions base/error.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ throw

Raise an `ErrorException` with the given message.
"""
error(s::AbstractString) = throw(ErrorException(s))
function error(s::AbstractString)
@_noinline_meta
@_hide_in_stacktrace_meta
throw(ErrorException(s))
end

"""
error(msg...)
Expand All @@ -39,6 +43,7 @@ Raise an `ErrorException` with the given message.
"""
function error(s::Vararg{Any,N}) where {N}
@_noinline_meta
@_hide_in_stacktrace_meta
throw(ErrorException(Main.Base.string(s...)))
end

Expand Down Expand Up @@ -106,8 +111,10 @@ Get a backtrace object for the current program point.
"""
function backtrace()
@_noinline_meta
# skip frame for backtrace(). Note that for this to work properly,
# backtrace() itself must not be interpreted nor inlined.
@_hide_in_stacktrace_meta
# skip frame for backtrace(). Note that with `skip > 0` backtrace() must
# not be inlined to avoid loosing parent frames.
# We also tag it as hidden in case it gets interpreted.
skip = 1
bt1, bt2 = ccall(:jl_backtrace_from_here, Ref{SimpleVector}, (Cint, Cint), false, skip)
return _reformat_bt(bt1::Vector{Ptr{Cvoid}}, bt2::Vector{Any})
Expand Down
16 changes: 6 additions & 10 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -745,11 +745,6 @@ function show_backtrace(io::IO, t::Vector{Any})
end
end

function is_kw_sorter_name(name::Symbol)
sn = string(name)
return !startswith(sn, '#') && endswith(sn, "##kw")
end

function process_backtrace(t::Vector, limit::Int=typemax(Int); skipC = true)
n = 0
last_frame = StackTraces.UNKNOWN
Expand All @@ -762,25 +757,26 @@ function process_backtrace(t::Vector, limit::Int=typemax(Int); skipC = true)
else
lkups = StackTraces.lookup(lkups)
end
for lkup in lkups
if lkup === StackTraces.UNKNOWN
for frame in lkups
if frame === StackTraces.UNKNOWN
continue
end

if (lkup.from_c && skipC) || is_kw_sorter_name(lkup.func)
if StackTraces.is_hidden(frame) && skipC
continue
end
count += 1
if count > limit
break
end

if lkup.file != last_frame.file || lkup.line != last_frame.line || lkup.func != last_frame.func || lkup.linfo !== lkup.linfo
if frame.file != last_frame.file || frame.line != last_frame.line ||
frame.func != last_frame.func || frame.linfo !== last_frame.linfo
if n > 0
push!(ret, (last_frame, n))
end
n = 1
last_frame = lkup
last_frame = frame
else
n += 1
end
Expand Down
3 changes: 3 additions & 0 deletions base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ end
macro _propagate_inbounds_meta()
return Expr(:meta, :inline, :propagate_inbounds)
end
macro _hide_in_stacktrace_meta()
return Expr(:meta, :hide_in_stacktrace)
end

function iterate end

Expand Down
12 changes: 12 additions & 0 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,18 @@ macro pure(ex)
esc(isa(ex, Expr) ? pushmeta!(ex, :pure) : ex)
end

"""
@hide_in_stacktrace
Mark a function to be hidden from the user in stacktraces. `@hide_in_stacktrace`
currently implies `@noinline`, though this may be relaxed in the future.
See also [`stacktrace`](@ref).
"""
macro hide_in_stacktrace(ex)
esc(ex isa Expr ? pushmeta!(pushmeta!(ex, :hide_in_stacktrace), :noinline) : ex)
end

"""
@propagate_inbounds
Expand Down
29 changes: 28 additions & 1 deletion base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1123,7 +1123,34 @@ The optional first argument `mapexpr` can be used to transform the included code
it is evaluated: for each parsed expression `expr` in `path`, the `include` function
actually evaluates `mapexpr(expr)`. If it is omitted, `mapexpr` defaults to [`identity`](@ref).
"""
Base.include # defined in sysimg.jl
Base.include # defined in Base.jl

# Full include() implementation which is used after bootstrap
# Hidden for nicer backtraces in include()
@hide_in_stacktrace function _include(mapexpr::Function, mod::Module, _path::AbstractString)
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)
if mapexpr === identity
result = ccall(:jl_load, Any, (Any, Cstring), mod, path)
else
result = ccall(:jl_load_rewrite, Any, (Any, Cstring, Any), mod, path, mapexpr)
end
finally
if prev === nothing
delete!(tls, :SOURCE_PATH)
else
tls[:SOURCE_PATH] = prev
end
end
return result
end

"""
evalfile(path::AbstractString, args::Vector{String}=String[])
Expand Down
42 changes: 27 additions & 15 deletions base/stacktraces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,20 @@ function hash(frame::StackFrame, h::UInt)
return h
end

# Determine whether frame should be hidden from the user by default
function is_hidden(frame::StackFrame)
if frame.from_c
return true
end
if frame.linfo isa Core.MethodInstance
# NB: MethodInstance currently only available for non-inlined frames.
def = frame.linfo.def
if def isa Method
return ccall(:jl_ir_flag_hide_in_stacktrace, Bool, (Any,), def.source)
end
end
return false
end

"""
lookup(pointer::Ptr{Cvoid}) -> Vector{StackFrame}
Expand Down Expand Up @@ -151,32 +165,30 @@ function lookup(ip::Base.InterpreterIP)
end

"""
stacktrace([trace::Vector{Ptr{Cvoid}},] [c_funcs::Bool=false]) -> StackTrace
stacktrace([rawtrace,] internal_funcs=false)

Returns a stack trace in the form of a vector of `StackFrame`s from the current
call stack, or from a raw call stack `rawtrace` which must have been previously
collected using `backtrace()`.

Returns a stack trace in the form of a vector of `StackFrame`s. (By default stacktrace
doesn't return C functions, but this can be enabled.) When called without specifying a
trace, `stacktrace` first calls `backtrace`.
By default `stacktrace` filters out internal functions, including C functions
and any Julia functions marked with `Base.@hide_in_stacktrace`. These can be
included by setting `internal_funcs` to `true`.
"""
function stacktrace(trace::Vector{<:Union{Base.InterpreterIP,Ptr{Cvoid}}}, c_funcs::Bool=false)
function stacktrace(rawtrace::AbstractVector, internal_funcs::Bool=false)
stack = StackTrace()
for ip in trace
for ip in rawtrace
for frame in lookup(ip)
# Skip frames that come from C calls.
if c_funcs || !frame.from_c
if internal_funcs || !is_hidden(frame)
push!(stack, frame)
end
end
end
return stack
end

function stacktrace(c_funcs::Bool=false)
stack = stacktrace(backtrace(), c_funcs)
# Remove frame for this function (and any functions called by this function).
remove_frames!(stack, :stacktrace)
# also remove all of the non-Julia functions that led up to this point (if that list is non-empty)
c_funcs && deleteat!(stack, 1:(something(findfirst(frame -> !frame.from_c, stack), 1) - 1))
return stack
@noinline Base.@hide_in_stacktrace function stacktrace(internal_funcs::Bool=false)
stacktrace(backtrace(), internal_funcs)
end

"""
Expand Down
2 changes: 2 additions & 0 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ jl_sym_t *throw_undef_if_not_sym; jl_sym_t *getfield_undefref_sym;
jl_sym_t *gc_preserve_begin_sym; jl_sym_t *gc_preserve_end_sym;
jl_sym_t *coverageeffect_sym; jl_sym_t *escape_sym;
jl_sym_t *aliasscope_sym; jl_sym_t *popaliasscope_sym;
jl_sym_t *hide_in_stacktrace_sym;

static uint8_t flisp_system_image[] = {
#include <julia_flisp.boot.inc>
Expand Down Expand Up @@ -368,6 +369,7 @@ void jl_init_frontend(void)
copyast_sym = jl_symbol("copyast");
loopinfo_sym = jl_symbol("loopinfo");
pure_sym = jl_symbol("pure");
hide_in_stacktrace_sym = jl_symbol("hide_in_stacktrace");
meta_sym = jl_symbol("meta");
list_sym = jl_symbol("list");
unused_sym = jl_symbol("#unused#");
Expand Down
13 changes: 12 additions & 1 deletion src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -2565,7 +2565,8 @@ JL_DLLEXPORT jl_array_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code)
NULL
};

uint8_t flags = (code->inferred << 3)
uint8_t flags = (code->hide_in_stacktrace << 4)
| (code->inferred << 3)
| (code->inlineable << 2)
| (code->propagate_inbounds << 1)
| (code->pure << 0);
Expand Down Expand Up @@ -2651,6 +2652,7 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t

jl_code_info_t *code = jl_new_code_info_uninit();
uint8_t flags = read_uint8(s.s);
code->hide_in_stacktrace = !!(flags & (1 << 4));
code->inferred = !!(flags & (1 << 3));
code->inlineable = !!(flags & (1 << 2));
code->propagate_inbounds = !!(flags & (1 << 1));
Expand Down Expand Up @@ -2704,6 +2706,15 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t
return code;
}

JL_DLLEXPORT uint8_t jl_ir_flag_hide_in_stacktrace(jl_array_t *data)
{
if (jl_is_code_info(data))
return ((jl_code_info_t*)data)->hide_in_stacktrace;
assert(jl_typeis(data, jl_array_uint8_type));
uint8_t flags = ((uint8_t*)data->data)[0];
return !!(flags & (1 << 4));
}

JL_DLLEXPORT uint8_t jl_ir_flag_inferred(jl_array_t *data)
{
if (jl_is_code_info(data))
Expand Down
8 changes: 5 additions & 3 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2080,7 +2080,7 @@ void jl_init_types(void) JL_GC_DISABLED
jl_code_info_type =
jl_new_datatype(jl_symbol("CodeInfo"), core,
jl_any_type, jl_emptysvec,
jl_perm_symsvec(18,
jl_perm_symsvec(19,
"code",
"codelocs",
"ssavaluetypes",
Expand All @@ -2095,11 +2095,12 @@ void jl_init_types(void) JL_GC_DISABLED
"edges",
"min_world",
"max_world",
"hide_in_stacktrace",
"inferred",
"inlineable",
"propagate_inbounds",
"pure"),
jl_svec(18,
jl_svec(19,
jl_array_any_type,
jl_any_type,
jl_any_type,
Expand All @@ -2117,8 +2118,9 @@ void jl_init_types(void) JL_GC_DISABLED
jl_bool_type,
jl_bool_type,
jl_bool_type,
jl_bool_type,
jl_bool_type),
0, 1, 18);
0, 1, 19);

jl_method_type =
jl_new_datatype(jl_symbol("Method"), core,
Expand Down
2 changes: 2 additions & 0 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@
name positional-sparams pargl-all
`(block
,@(without-generated prologue)
(meta hide_in_stacktrace)
,(let (;; call mangled(vals..., [rest_kw,] pargs..., [vararg]...)
(ret `(return (call ,mangled
,@(if ordered-defaults keynames vals)
Expand All @@ -519,6 +520,7 @@
(call (core kwftype) ,ftype)) ,kw ,@pargl ,@vararg)
`(block
,@(filter linenum? prologue)
(meta hide_in_stacktrace)
,(scopenest
keynames
(map (lambda (v dflt)
Expand Down
2 changes: 2 additions & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ typedef struct _jl_code_info_t {
size_t min_world;
size_t max_world;
// various boolean properties:
uint8_t hide_in_stacktrace;
uint8_t inferred;
uint8_t inlineable;
uint8_t propagate_inbounds;
Expand Down Expand Up @@ -1651,6 +1652,7 @@ JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr JL_MAYBE_UNROOTED);
// IR representation
JL_DLLEXPORT jl_array_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code);
JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t *metadata, jl_array_t *data);
JL_DLLEXPORT uint8_t jl_ir_flag_hide_in_stacktrace(jl_array_t *data) JL_NOTSAFEPOINT;
JL_DLLEXPORT uint8_t jl_ir_flag_inferred(jl_array_t *data) JL_NOTSAFEPOINT;
JL_DLLEXPORT uint8_t jl_ir_flag_inlineable(jl_array_t *data) JL_NOTSAFEPOINT;
JL_DLLEXPORT uint8_t jl_ir_flag_pure(jl_array_t *data) JL_NOTSAFEPOINT;
Expand Down
Loading