Skip to content

Commit

Permalink
implement Memory{T} as a new backend for Array{T} (#51319)
Browse files Browse the repository at this point in the history
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 #24909

Co-authored-by: Jameson Nash <vtjnash@gmail.com>
  • Loading branch information
oscardssmith and vtjnash authored Oct 27, 2023
1 parent 58030da commit 909bcea
Show file tree
Hide file tree
Showing 128 changed files with 5,996 additions and 5,351 deletions.
58 changes: 39 additions & 19 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@ using Core.Intrinsics, Core.IR

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

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

# array structures
include("indices.jl")
include("genericmemory.jl")
include("array.jl")
include("abstractarray.jl")
include("subarray.jl")
include("views.jl")
include("baseext.jl")

include("c.jl")
include("ntuple.jl")

include("abstractdict.jl")
include("iddict.jl")
include("idset.jl")

include("iterators.jl")
using .Iterators: zip, enumerate, only
using .Iterators: Flatten, Filter, product # for generators
using .Iterators: Stateful # compat (was formerly used in reinterpretarray.jl)

include("namedtuple.jl")

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

# numeric operations
include("hashing.jl")
Expand Down Expand Up @@ -271,24 +291,24 @@ include("set.jl")

# Strings
include("char.jl")
function array_new_memory(mem::Memory{UInt8}, newlen::Int)
# add an optimization to array_new_memory for StringVector
if (@assume_effects :total @ccall jl_genericmemory_owner(mem::Any,)::Any) isa String
# If data is in a String, keep it that way.
# When implemented, this could use jl_gc_expand_string(oldstr, newlen) as an optimization
str = _string_n(newlen)
return (@assume_effects :total !:consistent @ccall jl_string_to_genericmemory(str::Any,)::Memory{UInt8})
else
# TODO: when implemented, this should use a memory growing call
return typeof(mem)(undef, newlen)
end
end
include("strings/basic.jl")
include("strings/string.jl")
include("strings/substring.jl")

# Initialize DL_LOAD_PATH as early as possible. We are defining things here in
# a slightly more verbose fashion than usual, because we're running so early.
const DL_LOAD_PATH = String[]
let os = ccall(:jl_get_UNAME, Any, ())
if os === :Darwin || os === :Apple
if Base.DARWIN_FRAMEWORK
push!(DL_LOAD_PATH, "@loader_path/Frameworks")
end
push!(DL_LOAD_PATH, "@loader_path")
end
end
include("strings/cstring.jl")

include("osutils.jl")
include("c.jl")

# Core I/O
include("io.jl")
Expand Down
11 changes: 6 additions & 5 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@ julia> ndims(A)
3
```
"""
ndims(::AbstractArray{T,N}) where {T,N} = N
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N
ndims(::AbstractArray{T,N}) where {T,N} = N::Int
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N::Int
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))

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

throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I)))

# check along a single dimension
"""
checkindex(Bool, inds::AbstractUnitRange, index)
Expand Down Expand Up @@ -1451,6 +1449,8 @@ function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) whe
r
end

_unsetindex!(A::AbstractArray, i::Integer) = _unsetindex!(A, to_index(i))

"""
parent(A)
Expand Down Expand Up @@ -1556,7 +1556,8 @@ their component parts. A typical definition for an array that wraps a parent is
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
"""
dataids(A::AbstractArray) = (UInt(objectid(A)),)
dataids(A::Array) = (UInt(pointer(A)),)
dataids(A::Memory) = (B = ccall(:jl_genericmemory_owner, Any, (Any,), A); (UInt(pointer(B isa typeof(A) ? B : A)),))
dataids(A::Array) = dataids(A.ref.mem)
dataids(::AbstractRange) = ()
dataids(x) = ()

Expand Down
Loading

2 comments on commit 909bcea

@vtjnash
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nanosoldier runbenchmarks(ALL, isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here.

Please sign in to comment.