diff --git a/base/boot.jl b/base/boot.jl index 02b1e83739335..0f7c6dff06295 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -370,12 +370,38 @@ struct ErrorException <: Exception msg::AbstractString end +struct BoundsErrorSummary + desc::Union{Nothing,String} + size::Union{Nothing, Tuple{Vararg{Int}}} + atype::DataType + function BoundsErrorSummary(a) + # try to get a summary of `a` here now rather than capturing it for later inspection, + # in order to allow compiler analyses or optimization passes to assume the invariant + # that this `BoundsError` doesn't escape `a` when it is a certain primitive object + # that they can reason about + atype = typeof(a) + desc = nothing + size = nothing + if isa(a, Array) + size = a.size + elseif isa(a, GenericMemory) + size = (a.length,) + elseif isa(a, Tuple) + size = (nfields(a),) + elseif isdefined(Main, :Base) + desc = Main.Base.summary(a)::String + else + desc = "bootstraping threw `BoundsError` with unknown type $(atype). Please define `BoundsErrorSummary` on this type" + end + new(desc, size, atype) + end +end struct BoundsError <: Exception a::Any i::Any BoundsError() = new() - BoundsError(@nospecialize(a)) = (@noinline; new(a)) - BoundsError(@nospecialize(a), i) = (@noinline; new(a,i)) + BoundsError(a) = new(BoundsErrorSummary(a)) + BoundsError(a, i) = new(BoundsErrorSummary(a),i) end struct DivideError <: Exception end struct OutOfMemoryError <: Exception end diff --git a/base/errorshow.jl b/base/errorshow.jl index 64601ea35f548..e66241b50de56 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -56,7 +56,23 @@ function showerror(io::IO, ex::BoundsError) print(io, "BoundsError") if isdefined(ex, :a) print(io, ": attempt to access ") - summary(io, ex.a) + a = ex.a + if isa(a, Core.BoundsErrorSummary) + if isnothing(a.desc) + if length(a.size) == 1 + print(io, only(a.size)) + print(io, "-element ") + else + join(io, a.size, '×') + print(io, ' ') + end + print(io, a.atype) + else + print(io, a.desc) + end + else + summary(io, a) + end if isdefined(ex, :i) print(io, " at index [") if ex.i isa AbstractRange diff --git a/src/codegen.cpp b/src/codegen.cpp index a736449813608..7f92c5cff3f33 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -812,12 +812,6 @@ static const auto jlhasnofield_func = new JuliaFunction<>{ PointerType::get(JuliaType::get_jlvalue_ty(C), AddressSpace::CalleeRooted)}, false); }, get_attrs_noreturn, }; -static const auto jlboundserrorv_func = new JuliaFunction{ - XSTR(jl_bounds_error_ints), - [](LLVMContext &C, Type *T_size) { return FunctionType::get(getVoidTy(C), - {PointerType::get(JuliaType::get_jlvalue_ty(C), AddressSpace::CalleeRooted), PointerType::getUnqual(T_size->getContext()), T_size}, false); }, - get_attrs_noreturn, -}; static const auto jlboundserror_func = new JuliaFunction{ XSTR(jl_bounds_error_int), [](LLVMContext &C, Type *T_size) { return FunctionType::get(getVoidTy(C), @@ -9973,7 +9967,6 @@ static void init_jit_functions(void) add_named_global(jlthrow_func, &jl_throw); add_named_global(jlundefvarerror_func, &jl_undefined_var_error); add_named_global(jlhasnofield_func, &jl_has_no_field_error); - add_named_global(jlboundserrorv_func, &jl_bounds_error_ints); add_named_global(jlboundserror_func, &jl_bounds_error_int); add_named_global(jlvboundserror_func, &jl_bounds_error_tuple_int); add_named_global(jluboundserror_func, &jl_bounds_error_unboxed_int); diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index ea6f4c38f7f70..ca862d7025d69 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -46,7 +46,6 @@ XX(jl_boundp) \ XX(jl_bounds_error) \ XX(jl_bounds_error_int) \ - XX(jl_bounds_error_ints) \ XX(jl_bounds_error_tuple_int) \ XX(jl_bounds_error_unboxed_int) \ XX(jl_bounds_error_v) \ diff --git a/src/julia.h b/src/julia.h index fff465b0ab114..9011064721d41 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2173,8 +2173,6 @@ JL_DLLEXPORT void JL_NORETURN jl_bounds_error_int(jl_value_t *v JL_MAYBE_UNROOTE JL_DLLEXPORT void JL_NORETURN jl_bounds_error_tuple_int(jl_value_t **v, size_t nv, size_t i); JL_DLLEXPORT void JL_NORETURN jl_bounds_error_unboxed_int(void *v, jl_value_t *vt, size_t i); -JL_DLLEXPORT void JL_NORETURN jl_bounds_error_ints(jl_value_t *v JL_MAYBE_UNROOTED, - size_t *idxs, size_t nidxs); #define JL_NARGS(fname, min, max) \ if (nargs < min) jl_too_few_args(#fname, min); \ diff --git a/src/rtutils.c b/src/rtutils.c index e3672ab5d887e..82f76036c8767 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -216,20 +216,6 @@ JL_DLLEXPORT void JL_NORETURN jl_bounds_error_int(jl_value_t *v JL_MAYBE_UNROOTE jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t)); } -JL_DLLEXPORT void JL_NORETURN jl_bounds_error_ints(jl_value_t *v JL_MAYBE_UNROOTED, - size_t *idxs, size_t nidxs) -{ - size_t i; - jl_value_t *t = NULL; - JL_GC_PUSH2(&v, &t); // root arguments so the caller doesn't need to - t = (jl_value_t*)jl_alloc_svec(nidxs); - for (i = 0; i < nidxs; i++) { - jl_svecset(t, i, jl_box_long(idxs[i])); - } - t = jl_f_tuple(NULL, jl_svec_data(t), nidxs); - jl_throw(jl_new_struct((jl_datatype_t*)jl_boundserror_type, v, t)); -} - JL_DLLEXPORT void jl_typeassert(jl_value_t *x, jl_value_t *t) { if (!jl_isa(x,t)) diff --git a/test/boundscheck_exec.jl b/test/boundscheck_exec.jl index e3d5e77c05384..5c4a0f267aaf5 100644 --- a/test/boundscheck_exec.jl +++ b/test/boundscheck_exec.jl @@ -261,7 +261,8 @@ end getindex_40281(v, a, b, c) = @inbounds getindex(v, a, b, c) llvm_40281 = sprint((io, args...) -> code_llvm(io, args...; optimize=true), getindex_40281, Tuple{Array{Float64, 3}, Int, UInt8, Int}) if bc_opt == bc_default || bc_opt == bc_off - @test !occursin("call void @ijl_bounds_error_ints", llvm_40281) + @test !occursin("call void @ijl_bounds_error_int", llvm_40281) + @test !occursin("call void @j_throw_boundserror", llvm_40281) end # Given this is a sub-processed test file, not using @testsets avoids