Hi,
I wanted to ask about unsafe_pointer_to_objref, or alternatives. Naively, I would expect this to be a NOP for Ptr{T} if T is not bitstype, and otherwise a single load.
Is there a way to get the NOP behaviour? Is there a way to force types, that is, perform a type assertion which is guaranteed to emit no code (either re-interpret by nop or memory-corrupt if my assumptions where wrong)?
Now, why would I want this? Of course to store unsafe object references in immutable bitstypes. This allows, for example, allocation-free unsafe SubArrays.
Say, e.g.:
import Base.size, Base.getindex, Base.setindex!, Base.indices, Base.IndexStyle
immutable evil_aptr{T,N}<:AbstractArray{T,N}
aptr::Ptr{Array{T,N}}
end
@inline evil_aptr(x::Array{T,N}) where {T,N} = evil_aptr{T,N}(pointer_from_objref(x))
@inline size(a:: evil_aptr) = size(evil_deref(a))
@inline getindex(a:: evil_aptr, i)= getindex(evil_deref(a), i)
@inline getindex(a:: evil_aptr, i...)= getindex(evil_deref(a), i...)
@inline setindex!(a::evil_aptr, i) = setindex!(evil_deref(a), i)
@inline setindex!(a::evil_aptr, i...) = setindex!(evil_deref(a), i...)
@inline IndexStyle(evil_aptr) = IndexLinear()
@inline indices(a::evil_aptr) = indices(evil_deref(a))
@inline evil_deref(a::evil_aptr{T,N}) where {T,N} = unsafe_pointer_to_objref(a.aptr)::Array{T,N}
Now, subarrays of this unsafe aray are bitstype and don’t need heap-allocation:
@noinline function testsum(arr::AbstractArray{T,1}) where {T}
sum_i ::T= zero(T)
for i in arr
sum_i += i
end
return sum_i
end
function test_subarray(a::AbstractArray{T,1}) where {T}
sum_ ::T= zero(T)
for i in 1:length(a)-100
sum_ += testsum(view(a, i:i+100))
end
return sum_
end
X = Vector{Int}(100_000)
Xptr = evil_aptr(X)
test_subarray(X)
test_subarray(Xptr)
gc()
@time val1 = test_subarray(X)
@time val2 = test_subarray(Xptr)
assert(val1==val2)
0.029448 seconds (99.91 k allocations: 4.573 MiB)
0.034369 seconds (5 allocations: 176 bytes)
This is nice so far (no allocations), but real code using such a construction is quite slow. If it was possible to get a zero-overhead dereference for pointers to julia objects, then such things could actually work.
PS, for convenience: pointer.jl defines
unsafe_pointer_to_objref(x::Ptr) = ccall(:jl_value_ptr, Any, (Ptr{Void},), x)