From 7c7d49d86dc6129033dbcb3bfeba8b70a1daeb33 Mon Sep 17 00:00:00 2001 From: Carlo Baldassi Date: Tue, 6 Jan 2015 20:24:25 +0100 Subject: [PATCH] Manually manage inlining/noinlining of _checkbounds/BoundsError this should help avoiding unnecessary tuple allocations, i.e. delaying allocation until an error actually occurs --- base/abstractarray.jl | 14 +++++++++----- base/base.jl | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 2508e0f9ae007a..bc51ca8c3e46f0 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -75,13 +75,17 @@ linearindexing{A<:Array}(::Type{A}) = LinearFast() linearindexing{A<:Range}(::Type{A}) = LinearFast() ## Bounds checking ## -_checkbounds(sz::Int, i::Int, A::AbstractArray, J...) = 1 <= i <= sz || throw(BoundsError(A, J)) -_checkbounds(sz::Int, i::Real, A::AbstractArray, J...) = _checkbounds(sz, to_index(i), A, J...) -_checkbounds(sz::Int, I::AbstractVector{Bool}, A::AbstractArray, J...) = length(I) == sz || throw(BoundsError(A, J)) -_checkbounds(sz::Int, r::Range{Int}, A::AbstractArray, J...) = isempty(r) || (minimum(r) >= 1 && maximum(r) <= sz) || throw(BoundsError(A, J)) -_checkbounds{T<:Real}(sz::Int, r::Range{T}, A::AbstractArray, J...) = _checkbounds(sz, to_index(r), A, J...) +# note: we force inlining of all _checkbounds bethods in order to force splatting +# of the arguments and avoid allocating tuples (unless a BoundsError is raised). +# we can't use @inline at this stage in the build process, so we manually add :meta expressions +_checkbounds(sz::Int, i::Int, A::AbstractArray, J...) = (Expr(:meta, :inline); 1 <= i <= sz || throw(BoundsError(A, J))) +_checkbounds(sz::Int, i::Real, A::AbstractArray, J...) = (Expr(:meta, :inline); _checkbounds(sz, to_index(i), A, J...)) +_checkbounds(sz::Int, I::AbstractVector{Bool}, A::AbstractArray, J...) = (Expr(:meta, :inline); length(I) == sz || throw(BoundsError(A, J))) +_checkbounds(sz::Int, r::Range{Int}, A::AbstractArray, J...) = (Expr(:meta, :inline); isempty(r) || (minimum(r) >= 1 && maximum(r) <= sz) || throw(BoundsError(A, J))) +_checkbounds{T<:Real}(sz::Int, r::Range{T}, A::AbstractArray, J...) = (Expr(:meta, :inline); _checkbounds(sz, to_index(r), A, J...)) function _checkbounds{T <: Real}(sz::Int, I::AbstractArray{T}, A::AbstractArray, J...) + Expr(:meta, :inline) for i in I _checkbounds(sz, i, A, J...) end diff --git a/base/base.jl b/base/base.jl index daf59b0f9433aa..9d7860a0ae93b9 100644 --- a/base/base.jl +++ b/base/base.jl @@ -6,7 +6,8 @@ const Bottom = Union() # constructors for Core types in boot.jl call(T::Type{BoundsError}) = Core.call(T) -call(T::Type{BoundsError}, args...) = Core.call(T, args...) +# note: manual @noinline to avoid tuple allocations unless an error actually occurs +call(T::Type{BoundsError}, args...) = (Expr(:meta, :noinline); Core.call(T, args...)) call(T::Type{DivideError}) = Core.call(T) call(T::Type{DomainError}) = Core.call(T) call(T::Type{OverflowError}) = Core.call(T)