-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ptr
doesn't observe the supertype semantics of Ref
#49004
Comments
While we're at it, go ahead and try for the supertype of a data type LLVMPtr. Eltype doesn't propagate to supertype |
Yes,
|
It's mostly used in the LLVM.jl ecossystem |
Fixing this would probably be a good time to address some missing features in our memory system. For example, it might be helpful to have something like |
About a month ago I spent a weekend going through Rust's internals and playing around with some concepts and implementations for pointer types in Julia. I've been letting the ideas incubate for a while and refining it down to some basic principles that are more Julia-like. I think we all are on the same page that we shouldn't add abstract type AbstractPtr{T} <: Ref{T} end
if Core.sizeof(Int) == 8
primitive type Ptr{T} <: AbstractPtr{T} 8 end
else
primitive type Ptr{T} <: AbstractPtr{T} 4 end
end
struct NonNull{T} <: AbstractPtr{T}
ptr::Ptr{T}
function unsafe_convert(::Type{NonNull{T}}, ptr) where {T}
new{T}(ptr)
end
end
struct BoxPtr{T} <: AbstractPtr{T}
ptr::NonNull{Ptr{Cvoid}}
function unsafe_convert(::Type{BoxPtr{T}}, ptr) where {T}
new{T}(unsafe_convert(NonNull{Ptr{Cvoid}}, ptr))
end
end
Base.getindex(x::NonNull) = unsafe_load(x.ptr)
function Base.getindex(x::BoxPtr)
rawptr = x.ptr[]
rawptr === C_NULL && throw(UndefRefError())
ccall(:jl_value_ptr, Any, (Ptr{Cvoid},), rawptr)
end Without doing more complex compiler passes, I think this is about as much safety as rust provides for its pointers. There's no way to guarantee outside of site of construction of This doesn't ensure that GC doesn't happen, so I don't know if this goes far enough to ensure safety though. If not, then it might still be worth having these just have an |
Guaranteeing that a pointer is non-null is not enough though - you can have invalid pointers of any value. I don't think having a type specific for saying "this is non-null" is enough for that kind of semantic, because the name implies nothing at all about the pointer being valid or not, or who's responsible for that invariant. I vastly prefer the
This is a bad query; it restricts us to only being able to represent pointers on 64 and 32 bit systems, not to mention systems where pointersize and integer word-size don't match. I don't think we should leak that detail here - the pointersize ought to be something the runtime/compiler targetting a platform decides, not the host system julia happens to run on. |
Yeah, that's why I said we might need to still stick with that syntax. However, it does provide a bit more safety and structure even within the
This is just a small blurb for reference, imitating the annotations in "base/boot.jl". This would need to be defined in C. |
Yes; if you have some form of There's some added difficulty in that some platforms need to have some (somewhat) arbitrary pointers defined, because that's how their registers are exposed (common on microcontrollers, but whether we ever want to actually support that officially is another matter). A way out for that would of course be to have the abstraction "register" defined as a per-platform builtin, but that's starting to get a bit off-topic for this. |
I actually got interested more in the pointer stuff here after looking more into "src/codegen.cpp", but then following some of the conversations in LLVM it sounds like Rust was really pushing that stuff and potentially prototyping some behaviors to move into the compiler. One thing I'm not sure about is the overhead here. I've gleaned from some ongoing development conversations for LLVM that the large amount of bit casts are a large source of unnecessary overhead in system images. I think we can mitigate some of the compilation overhead but enforcing that specialization on loading these types is only done on Also, I don't think we currently support anything but 32 and 64 bit pointers. I'm not sure if that does need to be managed at this point to avoid a poor implementation. |
With GPUCompiler you can generate code for devices different from where Julia runs. |
This is super helpful to know. It also makes me wonder if we should have a pointer that is more flexible to that less intervention at the compiler level is necessary per device. struct RawPtr{T,A<:Union{UInt8, UInt16, UInt32, UInt64, UInt128}}
address::A
end |
With caveats, asterisks and all that stuff :') Cross compilation is just hard 🤷
As I understand it, that's what Before you go and abstract a pointer to just an address though, let me link you a few things so you have some context about where "pointers" as a concept in compiler land aare (likely) headed:
There's likely more up-to-date information on provenance than these, but that should get you started. The references in there are good too. |
It just keeps going :) |
I've stumbled across this unfortunate inconsistency:
In essence, we document that
Ref{T}
is guaranteed to point to valid julia allocated memory, which is not at all true ofPtr{T}
, butPtr{T} <: Ref{T}
still holds. There are other problems, likePtr
not havinggetindex
defined, as theRef
docstring claims:So at minimum,
Ptr
doesn't fulfill the API guaranteed byRef{T}
per the docstring.We could change the docstring of
Ref
toRef(x)
, and mention that theRef
abstract type does not make such a guarantee. Another option would be to change the name of theRef
type to something else (AbstractRef
?) and only keep theRef
function/type around as a shorthand forRefValue
, which is what it does now anyway (see@edit Ref(1)
). To keep the API the same, it would change from this:Ref{T}
Ptr{T}
RefValue{T}
RefArray{T}
to this:
AbstractRef{T}
Ptr{T}
Ref{T}
RefValue{T}
RefArray{T}
The issue with that is that we don't know whether someone relies on
Ptr{T} <: Ref{T}
somewhere (which they shouldn't, I think).The text was updated successfully, but these errors were encountered: