Skip to content

Commit 909bcea

Browse files
implement Memory{T} as a new backend for Array{T} (JuliaLang#51319)
See <https://hackmd.io/@vtjnash/rkzazi7an> for the Julep describing this change. Also makes memory allocation ccalls safer, for catching Serialization and deepcopy bugs in packages. Fixes JuliaLang#24909 Co-authored-by: Jameson Nash <[email protected]>
1 parent 58030da commit 909bcea

File tree

128 files changed

+5996
-5351
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+5996
-5351
lines changed

base/Base.jl

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,19 @@ using Core.Intrinsics, Core.IR
66

77
# to start, we're going to use a very simple definition of `include`
88
# that doesn't require any function (except what we can get from the `Core` top-module)
9-
const _included_files = Array{Tuple{Module,String},1}(Core.undef, 1)
9+
# start this big so that we don't have to resize before we have defined how to grow an array
10+
const _included_files = Array{Tuple{Module,String},1}(Core.undef, 400)
11+
setfield!(_included_files, :size, (1,))
1012
function include(mod::Module, path::String)
11-
ccall(:jl_array_grow_end, Cvoid, (Any, UInt), _included_files, UInt(1))
12-
Core.arrayset(true, _included_files, (mod, ccall(:jl_prepend_cwd, Any, (Any,), path)), arraylen(_included_files))
13+
len = getfield(_included_files.size, 1)
14+
memlen = _included_files.ref.mem.length
15+
lenp1 = Core.add_int(len, 1)
16+
if len === memlen # by the time this is true we hopefully will have defined _growend!
17+
_growend!(_included_files, UInt(1))
18+
else
19+
setfield!(_included_files, :size, (lenp1,))
20+
end
21+
Core.memoryrefset!(Core.memoryref(_included_files.ref, lenp1), (mod, ccall(:jl_prepend_cwd, Any, (Any,), path)), :not_atomic, true)
1322
Core.println(path)
1423
ccall(:jl_uv_flush, Nothing, (Ptr{Nothing},), Core.io_pointer(Core.stdout))
1524
Core.include(mod, path)
@@ -31,6 +40,7 @@ macro noinline() Expr(:meta, :noinline) end
3140
getproperty(x::Module, f::Symbol) = (@inline; getglobal(x, f))
3241
getproperty(x::Type, f::Symbol) = (@inline; getfield(x, f))
3342
setproperty!(x::Type, f::Symbol, v) = error("setfield! fields of Types should not be changed")
43+
setproperty!(x::Array, f::Symbol, v) = error("setfield! fields of Array should not be changed")
3444
getproperty(x::Tuple, f::Int) = (@inline; getfield(x, f))
3545
setproperty!(x::Tuple, f::Int, v) = setfield!(x, f, v) # to get a decent error
3646

@@ -192,23 +202,22 @@ include("strings/lazy.jl")
192202

193203
# array structures
194204
include("indices.jl")
205+
include("genericmemory.jl")
195206
include("array.jl")
196207
include("abstractarray.jl")
197208
include("subarray.jl")
198209
include("views.jl")
199210
include("baseext.jl")
200211

212+
include("c.jl")
201213
include("ntuple.jl")
202-
203214
include("abstractdict.jl")
204215
include("iddict.jl")
205216
include("idset.jl")
206-
207217
include("iterators.jl")
208218
using .Iterators: zip, enumerate, only
209219
using .Iterators: Flatten, Filter, product # for generators
210220
using .Iterators: Stateful # compat (was formerly used in reinterpretarray.jl)
211-
212221
include("namedtuple.jl")
213222

214223
# For OS specific stuff
@@ -224,6 +233,17 @@ function strcat(x::String, y::String)
224233
end
225234
include(strcat((length(Core.ARGS)>=2 ? Core.ARGS[2] : ""), "build_h.jl")) # include($BUILDROOT/base/build_h.jl)
226235
include(strcat((length(Core.ARGS)>=2 ? Core.ARGS[2] : ""), "version_git.jl")) # include($BUILDROOT/base/version_git.jl)
236+
# Initialize DL_LOAD_PATH as early as possible. We are defining things here in
237+
# a slightly more verbose fashion than usual, because we're running so early.
238+
const DL_LOAD_PATH = String[]
239+
let os = ccall(:jl_get_UNAME, Any, ())
240+
if os === :Darwin || os === :Apple
241+
if Base.DARWIN_FRAMEWORK
242+
push!(DL_LOAD_PATH, "@loader_path/Frameworks")
243+
end
244+
push!(DL_LOAD_PATH, "@loader_path")
245+
end
246+
end
227247

228248
# numeric operations
229249
include("hashing.jl")
@@ -271,24 +291,24 @@ include("set.jl")
271291

272292
# Strings
273293
include("char.jl")
294+
function array_new_memory(mem::Memory{UInt8}, newlen::Int)
295+
# add an optimization to array_new_memory for StringVector
296+
if (@assume_effects :total @ccall jl_genericmemory_owner(mem::Any,)::Any) isa String
297+
# If data is in a String, keep it that way.
298+
# When implemented, this could use jl_gc_expand_string(oldstr, newlen) as an optimization
299+
str = _string_n(newlen)
300+
return (@assume_effects :total !:consistent @ccall jl_string_to_genericmemory(str::Any,)::Memory{UInt8})
301+
else
302+
# TODO: when implemented, this should use a memory growing call
303+
return typeof(mem)(undef, newlen)
304+
end
305+
end
274306
include("strings/basic.jl")
275307
include("strings/string.jl")
276308
include("strings/substring.jl")
277-
278-
# Initialize DL_LOAD_PATH as early as possible. We are defining things here in
279-
# a slightly more verbose fashion than usual, because we're running so early.
280-
const DL_LOAD_PATH = String[]
281-
let os = ccall(:jl_get_UNAME, Any, ())
282-
if os === :Darwin || os === :Apple
283-
if Base.DARWIN_FRAMEWORK
284-
push!(DL_LOAD_PATH, "@loader_path/Frameworks")
285-
end
286-
push!(DL_LOAD_PATH, "@loader_path")
287-
end
288-
end
309+
include("strings/cstring.jl")
289310

290311
include("osutils.jl")
291-
include("c.jl")
292312

293313
# Core I/O
294314
include("io.jl")

base/abstractarray.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ julia> ndims(A)
268268
3
269269
```
270270
"""
271-
ndims(::AbstractArray{T,N}) where {T,N} = N
272-
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N
271+
ndims(::AbstractArray{T,N}) where {T,N} = N::Int
272+
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N::Int
273273
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
274274

275275
"""
@@ -731,8 +731,6 @@ end
731731
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
732732
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
733733

734-
throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I)))
735-
736734
# check along a single dimension
737735
"""
738736
checkindex(Bool, inds::AbstractUnitRange, index)
@@ -1451,6 +1449,8 @@ function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) whe
14511449
r
14521450
end
14531451

1452+
_unsetindex!(A::AbstractArray, i::Integer) = _unsetindex!(A, to_index(i))
1453+
14541454
"""
14551455
parent(A)
14561456
@@ -1556,7 +1556,8 @@ their component parts. A typical definition for an array that wraps a parent is
15561556
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
15571557
"""
15581558
dataids(A::AbstractArray) = (UInt(objectid(A)),)
1559-
dataids(A::Array) = (UInt(pointer(A)),)
1559+
dataids(A::Memory) = (B = ccall(:jl_genericmemory_owner, Any, (Any,), A); (UInt(pointer(B isa typeof(A) ? B : A)),))
1560+
dataids(A::Array) = dataids(A.ref.mem)
15601561
dataids(::AbstractRange) = ()
15611562
dataids(x) = ()
15621563

0 commit comments

Comments
 (0)