Skip to content

Commit

Permalink
Manually manage inlining/noinlining of _checkbounds/BoundsError
Browse files Browse the repository at this point in the history
this should help avoiding unnecessary tuple allocations, i.e.
delaying allocation until an error actually occurs
  • Loading branch information
carlobaldassi committed Jan 6, 2015
1 parent ebf94e3 commit 7c7d49d
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 6 deletions.
14 changes: 9 additions & 5 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion base/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 7c7d49d

Please sign in to comment.