Skip to content

Commit 7c4e441

Browse files
Reduce amount of LLVM code generated for specialized getindex (#31)
* Reduce amount of generated code by noinlineing * back to inlining but move large methods out of specialized code * fix ex throwing --------- Co-authored-by: Sacha Verweij <[email protected]>
1 parent 8026b8d commit 7c4e441

File tree

1 file changed

+30
-23
lines changed

1 file changed

+30
-23
lines changed

src/blob.jl

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ function Blob{T}(blob::Blob) where T
2424
Blob{T}(getfield(blob, :base), getfield(blob, :offset), getfield(blob, :limit))
2525
end
2626

27+
function Blob{T}(blob::Blob, rel_offset::Int64) where {T}
28+
Blob{T}(
29+
getfield(blob, :base),
30+
getfield(blob, :offset) + rel_offset,
31+
getfield(blob, :limit)
32+
)
33+
end
34+
2735
function assert_same_allocation(blob1::Blob, blob2::Blob)
2836
@noinline _throw(blob1, blob2) =
2937
throw(AssertionError("These blobs do not share the same allocation: $blob1 - $blob2"))
@@ -45,12 +53,20 @@ function Base.:-(blob1::Blob, blob2::Blob)
4553
getfield(blob1, :offset) - getfield(blob2, :offset)
4654
end
4755

48-
function boundscheck(blob::Blob{T}) where T
49-
begin
50-
if (getfield(blob, :offset) < 0) || (getfield(blob, :offset) + self_size(T) > getfield(blob, :limit))
51-
throw(BoundsError(blob))
52-
end
53-
@assert (getfield(blob, :base) != Ptr{Nothing}(0)) "Null pointer dereference in $(typeof(blob))"
56+
@noinline function _throw_assert_not_null_error(typename::Symbol)
57+
throw(AssertionError("Null pointer dereference in Blob{$(typename)}"))
58+
end
59+
60+
@noinline function boundscheck(blob::Blob{T}) where T
61+
base = getfield(blob, :base)
62+
offset = getfield(blob, :offset)
63+
limit = getfield(blob, :limit)
64+
element_size = self_size(T)
65+
if (offset < 0) || (offset + element_size > limit)
66+
throw(BoundsError())
67+
end
68+
if base == Ptr{Nothing}(0)
69+
_throw_assert_not_null_error(T.name.name)
5470
end
5571
end
5672

@@ -124,9 +140,12 @@ _fieldidx_lookup(::Type{T}, ::Val{field}, ::Val{i}) where {T,i,field} =
124140
Blob{FT}(blob + blob_offset(T, i))
125141
end
126142

143+
@noinline function _throw_getindex_boundserror(blob::Blob, i::Int)
144+
throw(BoundsError(blob, i))
145+
end
127146
@inline function Base.getindex(blob::Blob{T}, i::Int) where {T}
128147
@boundscheck if i < 1 || i > fieldcount(T)
129-
throw(BoundsError(blob, i))
148+
_throw_getindex_boundserror(blob, i)
130149
end
131150
return Blob{fieldtype(T, i)}(blob + Blobs.blob_offset(T, i))
132151
end
@@ -169,33 +188,21 @@ end
169188
unsafe_store!(pointer(blob), value)
170189
value
171190
else
172-
_unsafe_store_struct!(blob, value, Val(fieldcount(T)))
191+
_unsafe_store!(blob, value, Val(fieldcount(T)))
173192
value
174193
end
175194
end
176195
# On julia 1.11, this is equivalantly fast to the `@generated` version.
177196
# On julia 1.10, this is about 2x slower than generated for medium structs: ~10 ns vs ~5 ns.
178197
# We will go with the recursive version, to avoid the compilation cost.
179-
@inline _unsafe_store_struct!(::Blob{T}, ::T, ::Val{0}) where {T} = nothing
180-
function _unsafe_store_struct!(blob::Blob{T}, value::T, ::Val{I}) where {T, I}
198+
@inline _unsafe_store!(::Blob{T}, ::T, ::Val{0}) where {T} = nothing
199+
function _unsafe_store!(blob::Blob{T}, value::T, ::Val{I}) where {T, I}
181200
@inline
182201
types = fieldnames(T)
183-
_unsafe_store_struct!(blob, value, Val(I-1))
202+
_unsafe_store!(blob, value, Val(I-1))
184203
unsafe_store!(getindex(blob, types[I]), getproperty(value, types[I]))
185204
nothing
186205
end
187-
# Recursive function for tuples is equivalent to unrolled via `@generated`.
188-
function Base.unsafe_store!(blob::Blob{T}, value::T) where {T <: Tuple}
189-
_unsafe_store_tuple!(blob, value, Val(fieldcount(T)))
190-
value
191-
end
192-
@inline _unsafe_store_tuple!(::Blob{T}, ::T, ::Val{0}) where {T<:Tuple} = nothing
193-
function _unsafe_store_tuple!(blob::Blob{T}, value::T, ::Val{I}) where {T<:Tuple, I}
194-
@inline
195-
_unsafe_store_struct!(blob, value, Val(I-1))
196-
unsafe_store!(getindex(blob, I), value[I])
197-
nothing
198-
end
199206

200207
# if the value is the wrong type, try to convert it (just like setting a field normally)
201208
function Base.unsafe_store!(blob::Blob{T}, value) where {T}

0 commit comments

Comments
 (0)