| Line | Exclusive | Inclusive | Code |
|---|---|---|---|
| 1 | # This file is a part of Julia. License is MIT: https://julialang.org/license | ||
| 2 | |||
| 3 | """ | ||
| 4 | Ptr{T} | ||
| 5 | |||
| 6 | A memory address referring to data of type `T`. However, there is no guarantee that the | ||
| 7 | memory is actually valid, or that it actually represents data of the specified type. | ||
| 8 | """ | ||
| 9 | Ptr | ||
| 10 | |||
| 11 | ## converting pointers to an appropriate unsigned ## | ||
| 12 | |||
| 13 | """ | ||
| 14 | C_NULL | ||
| 15 | |||
| 16 | The C null pointer constant, sometimes used when calling external code. | ||
| 17 | """ | ||
| 18 | const C_NULL = bitcast(Ptr{Cvoid}, 0) | ||
| 19 | |||
| 20 | # TODO: deprecate these conversions. C doesn't even allow them. | ||
| 21 | |||
| 22 | # pointer to integer | ||
| 23 | convert(::Type{T}, x::Ptr) where {T<:Integer} = T(UInt(x))::T | ||
| 24 | |||
| 25 | # integer to pointer | ||
| 26 | convert(::Type{Ptr{T}}, x::Union{Int,UInt}) where {T} = Ptr{T}(x) | ||
| 27 | |||
| 28 | # pointer to pointer | ||
| 29 | convert(::Type{Ptr{T}}, p::Ptr{T}) where {T} = p | ||
| 30 | convert(::Type{Ptr{T}}, p::Ptr) where {T} = bitcast(Ptr{T}, p)::Ptr{T} | ||
| 31 | |||
| 32 | # object to pointer (when used with ccall) | ||
| 33 | |||
| 34 | """ | ||
| 35 | unsafe_convert(T, x) | ||
| 36 | |||
| 37 | Convert `x` to a C argument of type `T` | ||
| 38 | where the input `x` must be the return value of `cconvert(T, ...)`. | ||
| 39 | |||
| 40 | In cases where [`convert`](@ref) would need to take a Julia object | ||
| 41 | and turn it into a `Ptr`, this function should be used to define and perform | ||
| 42 | that conversion. | ||
| 43 | |||
| 44 | Be careful to ensure that a Julia reference to `x` exists as long as the result of this | ||
| 45 | function will be used. Accordingly, the argument `x` to this function should never be an | ||
| 46 | expression, only a variable name or field reference. For example, `x=a.b.c` is acceptable, | ||
| 47 | but `x=[a,b,c]` is not. | ||
| 48 | |||
| 49 | The `unsafe` prefix on this function indicates that using the result of this function after | ||
| 50 | the `x` argument to this function is no longer accessible to the program may cause undefined | ||
| 51 | behavior, including program corruption or segfaults, at any later time. | ||
| 52 | |||
| 53 | See also [`cconvert`](@ref) | ||
| 54 | """ | ||
| 55 | function unsafe_convert end | ||
| 56 | |||
| 57 | unsafe_convert(::Type{Ptr{UInt8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{UInt8}, (Any,), x) | ||
| 58 | unsafe_convert(::Type{Ptr{Int8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{Int8}, (Any,), x) | ||
| 59 | unsafe_convert(::Type{Ptr{UInt8}}, s::String) = ccall(:jl_string_ptr, Ptr{UInt8}, (Any,), s) | ||
| 60 | unsafe_convert(::Type{Ptr{Int8}}, s::String) = ccall(:jl_string_ptr, Ptr{Int8}, (Any,), s) | ||
| 61 | # convert strings to String etc. to pass as pointers | ||
| 62 | cconvert(::Type{Ptr{UInt8}}, s::AbstractString) = String(s) | ||
| 63 | cconvert(::Type{Ptr{Int8}}, s::AbstractString) = String(s) | ||
| 64 | |||
| 65 | unsafe_convert(::Type{Ptr{T}}, a::Array{T}) where {T} = ccall(:jl_array_ptr, Ptr{T}, (Any,), a) | ||
| 66 | unsafe_convert(::Type{Ptr{S}}, a::AbstractArray{T}) where {S,T} = convert(Ptr{S}, unsafe_convert(Ptr{T}, a)) | ||
| 67 | unsafe_convert(::Type{Ptr{T}}, a::AbstractArray{T}) where {T} = error("conversion to pointer not defined for $(typeof(a))") | ||
| 68 | |||
| 69 | # unsafe pointer to array conversions | ||
| 70 | """ | ||
| 71 | unsafe_wrap(Array, pointer::Ptr{T}, dims; own = false) | ||
| 72 | |||
| 73 | Wrap a Julia `Array` object around the data at the address given by `pointer`, | ||
| 74 | without making a copy. The pointer element type `T` determines the array | ||
| 75 | element type. `dims` is either an integer (for a 1d array) or a tuple of the array dimensions. | ||
| 76 | `own` optionally specifies whether Julia should take ownership of the memory, | ||
| 77 | calling `free` on the pointer when the array is no longer referenced. | ||
| 78 | |||
| 79 | This function is labeled "unsafe" because it will crash if `pointer` is not | ||
| 80 | a valid memory address to data of the requested length. Unlike [`unsafe_load`](@ref) | ||
| 81 | and [`unsafe_store!`](@ref), the programmer is responsible also for ensuring that the | ||
| 82 | underlying data is not accessed through two arrays of different element type, similar | ||
| 83 | to the strict aliasing rule in C. | ||
| 84 | """ | ||
| 85 | function unsafe_wrap(::Union{Type{Array},Type{Array{T}},Type{Array{T,N}}}, | ||
| 86 | p::Ptr{T}, dims::NTuple{N,Int}; own::Bool = false) where {T,N} | ||
| 87 | ccall(:jl_ptr_to_array, Array{T,N}, (Any, Ptr{Cvoid}, Any, Int32), | ||
| 88 | Array{T,N}, p, dims, own) | ||
| 89 | end | ||
| 90 | function unsafe_wrap(::Union{Type{Array},Type{Array{T}},Type{Array{T,1}}}, | ||
| 91 | p::Ptr{T}, d::Integer; own::Bool = false) where {T} | ||
| 92 | ccall(:jl_ptr_to_array_1d, Array{T,1}, | ||
| 93 | (Any, Ptr{Cvoid}, Csize_t, Cint), Array{T,1}, p, d, own) | ||
| 94 | end | ||
| 95 | unsafe_wrap(Atype::Union{Type{Array},Type{Array{T}},Type{Array{T,N}}}, | ||
| 96 | p::Ptr{T}, dims::NTuple{N,<:Integer}; own::Bool = false) where {T,N} = | ||
| 97 | unsafe_wrap(Atype, p, convert(Tuple{Vararg{Int}}, dims), own = own) | ||
| 98 | |||
| 99 | """ | ||
| 100 | unsafe_load(p::Ptr{T}, i::Integer=1) | ||
| 101 | unsafe_load(p::Ptr{T}, order::Symbol) | ||
| 102 | unsafe_load(p::Ptr{T}, i::Integer, order::Symbol) | ||
| 103 | |||
| 104 | Load a value of type `T` from the address of the `i`th element (1-indexed) starting at `p`. | ||
| 105 | This is equivalent to the C expression `p[i-1]`. Optionally, an atomic memory ordering can | ||
| 106 | be provided. | ||
| 107 | |||
| 108 | The `unsafe` prefix on this function indicates that no validation is performed on the | ||
| 109 | pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring | ||
| 110 | that referenced memory is not freed or garbage collected while invoking this function. | ||
| 111 | Incorrect usage may segfault your program or return garbage answers. Unlike C, dereferencing | ||
| 112 | memory region allocated as different type may be valid provided that the types are compatible. | ||
| 113 | |||
| 114 | !!! compat "Julia 1.10" | ||
| 115 | The `order` argument is available as of Julia 1.10. | ||
| 116 | |||
| 117 | See also: [`atomic`](@ref) | ||
| 118 | """ | ||
| 119 | 1 (2 %) | 1 (2 %) |
1 (2 %)
samples spent in unsafe_load
unsafe_load(p::Ptr, i::Integer=1) = pointerref(p, Int(i), 1)
1 (100 %) (ex.), 1 (100 %) (incl.) when called from getindex line 25 |
| 120 | unsafe_load(p::Ptr, order::Symbol) = atomic_pointerref(p, order) | ||
| 121 | function unsafe_load(p::Ptr, i::Integer, order::Symbol) | ||
| 122 | unsafe_load(p + (elsize(typeof(p)) * (Int(i) - 1)), order) | ||
| 123 | end | ||
| 124 | |||
| 125 | """ | ||
| 126 | unsafe_store!(p::Ptr{T}, x, i::Integer=1) | ||
| 127 | unsafe_store!(p::Ptr{T}, x, order::Symbol) | ||
| 128 | unsafe_store!(p::Ptr{T}, x, i::Integer, order::Symbol) | ||
| 129 | |||
| 130 | Store a value of type `T` to the address of the `i`th element (1-indexed) starting at `p`. | ||
| 131 | This is equivalent to the C expression `p[i-1] = x`. Optionally, an atomic memory ordering | ||
| 132 | can be provided. | ||
| 133 | |||
| 134 | The `unsafe` prefix on this function indicates that no validation is performed on the | ||
| 135 | pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring | ||
| 136 | that referenced memory is not freed or garbage collected while invoking this function. | ||
| 137 | Incorrect usage may segfault your program. Unlike C, storing memory region allocated as | ||
| 138 | different type may be valid provided that that the types are compatible. | ||
| 139 | |||
| 140 | !!! compat "Julia 1.10" | ||
| 141 | The `order` argument is available as of Julia 1.10. | ||
| 142 | |||
| 143 | See also: [`atomic`](@ref) | ||
| 144 | """ | ||
| 145 | unsafe_store!(p::Ptr{Any}, @nospecialize(x), i::Integer=1) = pointerset(p, x, Int(i), 1) | ||
| 146 | 1 (2 %) | 1 (2 %) |
1 (2 %)
samples spent in unsafe_store!
unsafe_store!(p::Ptr{T}, x, i::Integer=1) where {T} = pointerset(p, convert(T,x), Int(i), 1)
1 (100 %) (ex.), 1 (100 %) (incl.) when called from setindex! line 35 |
| 147 | unsafe_store!(p::Ptr{T}, x, order::Symbol) where {T} = atomic_pointerset(p, x isa T ? x : convert(T,x), order) | ||
| 148 | function unsafe_store!(p::Ptr, x, i::Integer, order::Symbol) | ||
| 149 | unsafe_store!(p + (elsize(typeof(p)) * (Int(i) - 1)), x, order) | ||
| 150 | end | ||
| 151 | |||
| 152 | """ | ||
| 153 | unsafe_modify!(p::Ptr{T}, op, x, [order::Symbol]) -> Pair | ||
| 154 | |||
| 155 | These atomically perform the operations to get and set a memory address after applying | ||
| 156 | the function `op`. If supported by the hardware (for example, atomic increment), this may be | ||
| 157 | optimized to the appropriate hardware instruction, otherwise its execution will be | ||
| 158 | similar to: | ||
| 159 | |||
| 160 | y = unsafe_load(p) | ||
| 161 | z = op(y, x) | ||
| 162 | unsafe_store!(p, z) | ||
| 163 | return y => z | ||
| 164 | |||
| 165 | The `unsafe` prefix on this function indicates that no validation is performed on the | ||
| 166 | pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring | ||
| 167 | that referenced memory is not freed or garbage collected while invoking this function. | ||
| 168 | Incorrect usage may segfault your program. | ||
| 169 | |||
| 170 | !!! compat "Julia 1.10" | ||
| 171 | This function requires at least Julia 1.10. | ||
| 172 | |||
| 173 | See also: [`modifyproperty!`](@ref Base.modifyproperty!), [`atomic`](@ref) | ||
| 174 | """ | ||
| 175 | function unsafe_modify!(p::Ptr, op, x, order::Symbol=:not_atomic) | ||
| 176 | return atomic_pointermodify(p, op, x, order) | ||
| 177 | end | ||
| 178 | |||
| 179 | """ | ||
| 180 | unsafe_replace!(p::Ptr{T}, expected, desired, | ||
| 181 | [success_order::Symbol[, fail_order::Symbol=success_order]]) -> (; old, success::Bool) | ||
| 182 | |||
| 183 | These atomically perform the operations to get and conditionally set a memory address to | ||
| 184 | a given value. If supported by the hardware, this may be optimized to the appropriate | ||
| 185 | hardware instruction, otherwise its execution will be similar to: | ||
| 186 | |||
| 187 | y = unsafe_load(p, fail_order) | ||
| 188 | ok = y === expected | ||
| 189 | if ok | ||
| 190 | unsafe_store!(p, desired, success_order) | ||
| 191 | end | ||
| 192 | return (; old = y, success = ok) | ||
| 193 | |||
| 194 | The `unsafe` prefix on this function indicates that no validation is performed on the | ||
| 195 | pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring | ||
| 196 | that referenced memory is not freed or garbage collected while invoking this function. | ||
| 197 | Incorrect usage may segfault your program. | ||
| 198 | |||
| 199 | !!! compat "Julia 1.10" | ||
| 200 | This function requires at least Julia 1.10. | ||
| 201 | |||
| 202 | See also: [`replaceproperty!`](@ref Base.replaceproperty!), [`atomic`](@ref) | ||
| 203 | """ | ||
| 204 | function unsafe_replace!(p::Ptr{T}, expected, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) where {T} | ||
| 205 | @inline | ||
| 206 | xT = desired isa T ? desired : convert(T, desired) | ||
| 207 | return atomic_pointerreplace(p, expected, xT, success_order, fail_order) | ||
| 208 | end | ||
| 209 | function unsafe_replace!(p::Ptr{Any}, @nospecialize(expected), @nospecialize(desired), success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) | ||
| 210 | return atomic_pointerreplace(p, expected, desired, success_order, fail_order) | ||
| 211 | end | ||
| 212 | |||
| 213 | """ | ||
| 214 | unsafe_swap!(p::Ptr{T}, x, [order::Symbol]) | ||
| 215 | |||
| 216 | These atomically perform the operations to simultaneously get and set a memory address. | ||
| 217 | If supported by the hardware, this may be optimized to the appropriate hardware | ||
| 218 | instruction, otherwise its execution will be similar to: | ||
| 219 | |||
| 220 | y = unsafe_load(p) | ||
| 221 | unsafe_store!(p, x) | ||
| 222 | return y | ||
| 223 | |||
| 224 | The `unsafe` prefix on this function indicates that no validation is performed on the | ||
| 225 | pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring | ||
| 226 | that referenced memory is not freed or garbage collected while invoking this function. | ||
| 227 | Incorrect usage may segfault your program. | ||
| 228 | |||
| 229 | !!! compat "Julia 1.10" | ||
| 230 | This function requires at least Julia 1.10. | ||
| 231 | |||
| 232 | See also: [`swapproperty!`](@ref Base.swapproperty!), [`atomic`](@ref) | ||
| 233 | """ | ||
| 234 | function unsafe_swap!(p::Ptr{Any}, x, order::Symbol=:not_atomic) | ||
| 235 | return atomic_pointerswap(p, x, order) | ||
| 236 | end | ||
| 237 | function unsafe_swap!(p::Ptr{T}, x, order::Symbol=:not_atomic) where {T} | ||
| 238 | @inline | ||
| 239 | xT = x isa T ? x : convert(T, x) | ||
| 240 | return atomic_pointerswap(p, xT, order) | ||
| 241 | end | ||
| 242 | |||
| 243 | # convert a raw Ptr to an object reference, and vice-versa | ||
| 244 | """ | ||
| 245 | unsafe_pointer_to_objref(p::Ptr) | ||
| 246 | |||
| 247 | Convert a `Ptr` to an object reference. Assumes the pointer refers to a valid heap-allocated | ||
| 248 | Julia object. If this is not the case, undefined behavior results, hence this function is | ||
| 249 | considered "unsafe" and should be used with care. | ||
| 250 | |||
| 251 | See also [`pointer_from_objref`](@ref). | ||
| 252 | """ | ||
| 253 | unsafe_pointer_to_objref(x::Ptr) = ccall(:jl_value_ptr, Any, (Ptr{Cvoid},), x) | ||
| 254 | |||
| 255 | """ | ||
| 256 | pointer_from_objref(x) | ||
| 257 | |||
| 258 | Get the memory address of a Julia object as a `Ptr`. The existence of the resulting `Ptr` | ||
| 259 | will not protect the object from garbage collection, so you must ensure that the object | ||
| 260 | remains referenced for the whole time that the `Ptr` will be used. | ||
| 261 | |||
| 262 | This function may not be called on immutable objects, since they do not have | ||
| 263 | stable memory addresses. | ||
| 264 | |||
| 265 | See also [`unsafe_pointer_to_objref`](@ref). | ||
| 266 | """ | ||
| 267 | function pointer_from_objref(@nospecialize(x)) | ||
| 268 | @inline | ||
| 269 | ismutable(x) || error("pointer_from_objref cannot be used on immutable objects") | ||
| 270 | ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x) | ||
| 271 | end | ||
| 272 | |||
| 273 | ## limited pointer arithmetic & comparison ## | ||
| 274 | |||
| 275 | isequal(x::Ptr, y::Ptr) = (x === y) | ||
| 276 | isless(x::Ptr{T}, y::Ptr{T}) where {T} = x < y | ||
| 277 | |||
| 278 | ==(x::Ptr, y::Ptr) = UInt(x) == UInt(y) | ||
| 279 | <(x::Ptr, y::Ptr) = UInt(x) < UInt(y) | ||
| 280 | -(x::Ptr, y::Ptr) = UInt(x) - UInt(y) | ||
| 281 | |||
| 282 | +(x::Ptr, y::Integer) = oftype(x, add_ptr(UInt(x), (y % UInt) % UInt)) | ||
| 283 | -(x::Ptr, y::Integer) = oftype(x, sub_ptr(UInt(x), (y % UInt) % UInt)) | ||
| 284 | +(x::Integer, y::Ptr) = y + x | ||
| 285 | |||
| 286 | unsigned(x::Ptr) = UInt(x) | ||
| 287 | signed(x::Ptr) = Int(x) |