Skip to content

Commit 6a3fef3

Browse files
committed
Add load/store aggregate functions
1 parent afc8a04 commit 6a3fef3

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

src/ManualMemory.jl

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ end
1717
Expr(:block, Expr(:meta,:inline), :(ccall(:jl_value_ptr, Ref{$T}, (Ptr{Cvoid},), unsafe_load(Base.unsafe_convert(Ptr{Ptr{Cvoid}}, p)))))
1818
end
1919
end
20+
@inline load(p::Ptr{UInt}, ::Type{T}) where {T} = load(reinterpret(Ptr{T}, p))
2021
@generated function store!(p::Ptr{T}, v::T) where {T}
2122
if Base.allocatedinline(T)
2223
Expr(:block, Expr(:meta,:inline), :(unsafe_store!(p, v); return nothing))
@@ -33,4 +34,71 @@ end
3334
@inline _preserve_buffer(a::A, p::A) where {A<:AbstractArray} = a
3435
@inline _preserve_buffer(a::A, p::P) where {A,P} = p
3536

37+
function load_aggregate(::Type{T}, offset::Int) where {T}
38+
numfields = fieldcount(T)
39+
call = (T <: Tuple) ? Expr(:tuple) : Expr(:new, T)
40+
for f 1:numfields
41+
TF = fieldtype(T, f)
42+
if Base.issingletontype(TF)
43+
push!(call.args, TF.instance)
44+
elseif fieldcount(TF) 0
45+
ptr = :(p + (offset + $offset))
46+
ptr = TF === UInt ? ptr : :(reinterpret(Ptr{$TF}, $ptr))
47+
push!(call.args, :(load($ptr)))
48+
offset += offsetsize(TF)
49+
else
50+
arg, offset = load_aggregate(TF, offset)
51+
push!(call.args, arg)
52+
end
53+
end
54+
return call, offset
55+
end
56+
@generated function load(p::Ptr{UInt}, ::Type{T}, offset::Int) where {T}
57+
if Base.issingletontype(T)
58+
call = Expr(:tuple, :offset, T.instance)
59+
elseif fieldcount(T) 0
60+
ptr = :(p + offset)
61+
ptr = T === UInt ? ptr : :(reinterpret(Ptr{$T}, $ptr))
62+
call = :(((offset + $(offsetsize(T)), load($ptr))))
63+
else
64+
call, off = load_aggregate(T, 0)
65+
call = Expr(:tuple, :(offset + $off), call)
66+
end
67+
Expr(:block, Expr(:meta,:inline), call)
68+
end
69+
70+
function store_aggregate!(q::Expr, sym, ::Type{T}, offset::Int) where {T}
71+
gf = GlobalRef(Core,:getfield)
72+
for f 1:fieldcount(T)
73+
TF = fieldtype(T, f)
74+
Base.issingletontype(TF) && continue
75+
gfcall = Expr(:call, gf, sym, f)
76+
if fieldcount(TF) 0
77+
ptr = :(p + (offset + $offset))
78+
ptr = TF === UInt ? ptr : :(reinterpret(Ptr{$TF}, $ptr))
79+
push!(q.args, :(store!($ptr, $gfcall)))
80+
offset += offsetsize(TF)
81+
else
82+
newsym = gensym(sym)
83+
push!(q.args, Expr(:(=), newsym, gfcall))
84+
offset = store_aggregate!(q, newsym, TF, offset)
85+
end
86+
end
87+
return offset
88+
end
89+
@generated function store!(p::Ptr{UInt}, x::T, offset::Int) where {T}
90+
Base.issingletontype(T) && return :offset
91+
body = Expr(:block, Expr(:meta,:inline))
92+
if fieldcount(T) 0
93+
ptr = :(p + offset)
94+
ptr = T === UInt ? ptr : :(reinterpret(Ptr{$T}, $ptr))
95+
push!(body.args, :(store!($ptr, x)))
96+
off = offsetsize(T)
97+
else
98+
off = store_aggregate!(body, :x, T, 0)
99+
end
100+
push!(body.args, Expr(:call, +, :offset, off))
101+
return body
102+
end
103+
36104
end

0 commit comments

Comments
 (0)