Skip to content

Commit 70a7da9

Browse files
authored
Merge pull request #16893 from JuliaLang/yyc/gc/array
Array resizing fixes and clean up
2 parents bf44142 + dd3ba9b commit 70a7da9

File tree

23 files changed

+658
-313
lines changed

23 files changed

+658
-313
lines changed

base/array.jl

Lines changed: 29 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ end
3636
## copy ##
3737

3838
function unsafe_copy!{T}(dest::Ptr{T}, src::Ptr{T}, n)
39+
# Do not use this to copy data between pointer arrays.
40+
# It can't be made safe no matter how carefully you checked.
3941
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt),
4042
dest, src, n*sizeof(T))
4143
return dest
@@ -45,9 +47,8 @@ function unsafe_copy!{T}(dest::Array{T}, doffs, src::Array{T}, soffs, n)
4547
if isbits(T)
4648
unsafe_copy!(pointer(dest, doffs), pointer(src, soffs), n)
4749
else
48-
for i=0:n-1
49-
@inbounds arrayset(dest, src[i+soffs], i+doffs)
50-
end
50+
ccall(:jl_array_ptr_copy, Void, (Any, Ptr{Void}, Any, Ptr{Void}, Int),
51+
dest, pointer(dest, doffs), src, pointer(src, soffs), n)
5152
end
5253
return dest
5354
end
@@ -63,11 +64,7 @@ end
6364

6465
copy!{T}(dest::Array{T}, src::Array{T}) = copy!(dest, 1, src, 1, length(src))
6566

66-
function copy(a::Array)
67-
b = similar(a)
68-
ccall(:memcpy, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt), b, a, sizeof(a))
69-
return b
70-
end
67+
copy{T<:Array}(a::T) = ccall(:jl_array_copy, Ref{T}, (Any,), a)
7168

7269
function reinterpret{T,S}(::Type{T}, a::Array{S,1})
7370
nel = Int(div(length(a)*sizeof(S),sizeof(T)))
@@ -389,66 +386,13 @@ setindex!{T, N}(A::Array{T, N}, x::Number, ::Vararg{Colon, N}) = fill!(A, x)
389386

390387
# efficiently grow an array
391388

392-
function _growat!(a::Vector, i::Integer, delta::Integer)
393-
n = length(a)
394-
if i < div(n,2)
395-
_growat_beg!(a, i, delta)
396-
else
397-
_growat_end!(a, i, delta)
398-
end
399-
return a
400-
end
401-
402-
function _growat_beg!(a::Vector, i::Integer, delta::Integer)
403-
ccall(:jl_array_grow_beg, Void, (Any, UInt), a, delta)
404-
if i > 1
405-
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, Csize_t),
406-
pointer(a, 1), pointer(a, 1+delta), (i-1)*elsize(a))
407-
end
408-
return a
409-
end
410-
411-
function _growat_end!(a::Vector, i::Integer, delta::Integer)
412-
ccall(:jl_array_grow_end, Void, (Any, UInt), a, delta)
413-
n = length(a)
414-
if n >= i+delta
415-
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, Csize_t),
416-
pointer(a, i+delta), pointer(a, i), (n-i-delta+1)*elsize(a))
417-
end
418-
return a
419-
end
389+
_growat!(a::Vector, i::Integer, delta::Integer) =
390+
ccall(:jl_array_grow_at, Void, (Any, Int, UInt), a, i - 1, delta)
420391

421392
# efficiently delete part of an array
422393

423-
function _deleteat!(a::Vector, i::Integer, delta::Integer)
424-
n = length(a)
425-
last = i+delta-1
426-
if i-1 < n-last
427-
_deleteat_beg!(a, i, delta)
428-
else
429-
_deleteat_end!(a, i, delta)
430-
end
431-
return a
432-
end
433-
434-
function _deleteat_beg!(a::Vector, i::Integer, delta::Integer)
435-
if i > 1
436-
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, Csize_t),
437-
pointer(a, 1+delta), pointer(a, 1), (i-1)*elsize(a))
438-
end
439-
ccall(:jl_array_del_beg, Void, (Any, UInt), a, delta)
440-
return a
441-
end
442-
443-
function _deleteat_end!(a::Vector, i::Integer, delta::Integer)
444-
n = length(a)
445-
if n >= i+delta
446-
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, Csize_t),
447-
pointer(a, i), pointer(a, i+delta), (n-i-delta+1)*elsize(a))
448-
end
449-
ccall(:jl_array_del_end, Void, (Any, UInt), a, delta)
450-
return a
451-
end
394+
_deleteat!(a::Vector, i::Integer, delta::Integer) =
395+
ccall(:jl_array_del_at, Void, (Any, Int, UInt), a, i - 1, delta)
452396

453397
## Dequeue functionality ##
454398

@@ -528,34 +472,20 @@ function shift!(a::Vector)
528472
end
529473

530474
function insert!{T}(a::Array{T,1}, i::Integer, item)
531-
if !(1 <= i <= length(a)+1)
532-
throw(BoundsError())
533-
end
534-
if i == length(a)+1
535-
return push!(a, item)
536-
end
537-
item = convert(T, item)
475+
# Throw convert error before changing the shape of the array
476+
_item = convert(T, item)
538477
_growat!(a, i, 1)
539-
a[i] = item
478+
# _growat! already did bound check
479+
@inbounds a[i] = _item
540480
return a
541481
end
542482

543-
function deleteat!(a::Vector, i::Integer)
544-
if !(1 <= i <= length(a))
545-
throw(BoundsError())
546-
end
547-
return _deleteat!(a, i, 1)
548-
end
483+
deleteat!(a::Vector, i::Integer) = (_deleteat!(a, i, 1); a)
549484

550485
function deleteat!{T<:Integer}(a::Vector, r::UnitRange{T})
551486
n = length(a)
552-
isempty(r) && return a
553-
f = first(r)
554-
l = last(r)
555-
if !(1 <= f && l <= n)
556-
throw(BoundsError())
557-
end
558-
return _deleteat!(a, f, length(r))
487+
isempty(r) || _deleteat!(a, first(r), length(r))
488+
return a
559489
end
560490

561491
function deleteat!(a::Vector, inds)
@@ -622,18 +552,9 @@ function splice!{T<:Integer}(a::Vector, r::UnitRange{T}, ins=_default_splice)
622552

623553
if m < d
624554
delta = d - m
625-
if f-1 < n-l
626-
_deleteat_beg!(a, f, delta)
627-
else
628-
_deleteat_end!(a, l-delta+1, delta)
629-
end
555+
_deleteat!(a, (f - 1 < n - l) ? f : (l - delta + 1), delta)
630556
elseif m > d
631-
delta = m - d
632-
if f-1 < n-l
633-
_growat_beg!(a, f, delta)
634-
else
635-
_growat_end!(a, l+1, delta)
636-
end
557+
_growat!(a, (f - 1 < n - l) ? f : (l + 1), m - d)
637558
end
638559

639560
k = 1
@@ -693,17 +614,22 @@ function vcat{T}(arrays::Vector{T}...)
693614
end
694615
arr = Array{T}(n)
695616
ptr = pointer(arr)
696-
offset = 0
697617
if isbits(T)
698-
elsz = sizeof(T)
618+
elsz = Core.sizeof(T)
699619
else
700620
elsz = Core.sizeof(Ptr{Void})
701621
end
702622
for a in arrays
703-
nba = length(a)*elsz
704-
ccall(:memcpy, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt),
705-
ptr+offset, a, nba)
706-
offset += nba
623+
na = length(a)
624+
nba = na * elsz
625+
if isbits(T)
626+
ccall(:memcpy, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt),
627+
ptr, a, nba)
628+
else
629+
ccall(:jl_array_ptr_copy, Void, (Any, Ptr{Void}, Any, Ptr{Void}, Int),
630+
arr, ptr, a, pointer(a), na)
631+
end
632+
ptr += nba
707633
end
708634
return arr
709635
end

base/c.jl

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,6 @@ if !is_windows()
4646
end
4747
end
4848

49-
# C NUL-terminated string pointers; these can be used in ccall
50-
# instead of Ptr{Cchar} and Ptr{Cwchar_t}, respectively, to enforce
51-
# a check for embedded NUL chars in the string (to avoid silent truncation).
52-
if Int === Int64
53-
bitstype 64 Cstring
54-
bitstype 64 Cwstring
55-
else
56-
bitstype 32 Cstring
57-
bitstype 32 Cwstring
58-
end
59-
6049
# construction from typed pointers
6150
convert{T<:Union{Int8,UInt8}}(::Type{Cstring}, p::Ptr{T}) = box(Cstring, p)
6251
convert(::Type{Cwstring}, p::Ptr{Cwchar_t}) = box(Cwstring, p)
@@ -80,20 +69,27 @@ unsafe_wrap(::Type{String}, p::Cstring, len::Integer, own::Bool=false) =
8069
unsafe_string(s::Cstring) = unsafe_string(convert(Ptr{UInt8}, s))
8170

8271
# convert strings to String etc. to pass as pointers
83-
cconvert(::Type{Cstring}, s::AbstractString) = String(s)
72+
cconvert(::Type{Cstring}, s::String) =
73+
ccall(:jl_array_cconvert_cstring, Ref{Vector{UInt8}},
74+
(Vector{UInt8},), s.data)
75+
cconvert(::Type{Cstring}, s::AbstractString) =
76+
cconvert(Cstring, String(s)::String)
8477

8578
function cconvert(::Type{Cwstring}, s::AbstractString)
8679
v = transcode(Cwchar_t, String(s).data)
8780
!isempty(v) && v[end] == 0 || push!(v, 0)
8881
return v
8982
end
9083

84+
eltype(::Type{Cstring}) = UInt8
85+
eltype(::Type{Cwstring}) = Cwchar_t
86+
9187
containsnul(p::Ptr, len) =
9288
C_NULL != ccall(:memchr, Ptr{Cchar}, (Ptr{Cchar}, Cint, Csize_t), p, 0, len)
9389
containsnul(s::String) = containsnul(unsafe_convert(Ptr{Cchar}, s), sizeof(s))
9490
containsnul(s::AbstractString) = '\0' in s
9591

96-
function unsafe_convert(::Type{Cstring}, s::String)
92+
function unsafe_convert(::Type{Cstring}, s::Vector{UInt8})
9793
p = unsafe_convert(Ptr{Cchar}, s)
9894
containsnul(p, sizeof(s)) &&
9995
throw(ArgumentError("embedded NULs are not allowed in C strings: $(repr(s))"))

base/libgit2/libgit2.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ function clone{P<:AbstractPayload}(repo_url::AbstractString, repo_path::Abstract
297297
remote_cb::Ptr{Void} = C_NULL,
298298
payload::Nullable{P}=Nullable{AbstractPayload}())
299299
# setup clone options
300-
lbranch = Base.cconvert(Cstring, String(branch))
300+
lbranch = Base.cconvert(Cstring, branch)
301301
fetch_opts=FetchOptions(callbacks = RemoteCallbacks(credentials_cb(), payload))
302302
clone_opts = CloneOptions(
303303
bare = Cint(isbare),

base/libgit2/oid.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function Oid(id::AbstractString)
2828
(Ptr{Oid}, Ptr{UInt8}, Csize_t), oid_ptr, bstr, len)
2929
else
3030
ccall((:git_oid_fromstrp, :libgit2), Cint,
31-
(Ptr{Oid}, Ptr{Cchar}), oid_ptr, bstr)
31+
(Ptr{Oid}, Cstring), oid_ptr, bstr)
3232
end
3333
err != 0 && return Oid()
3434
return oid_ptr[]
@@ -46,7 +46,7 @@ function Oid(repo::GitRepo, ref_name::AbstractString)
4646
isempty(repo) && return Oid()
4747
oid_ptr = Ref(Oid())
4848
@check ccall((:git_reference_name_to_id, :libgit2), Cint,
49-
(Ptr{Oid}, Ptr{Void}, Ptr{UInt8}),
49+
(Ptr{Oid}, Ptr{Void}, Cstring),
5050
oid_ptr, repo.ptr, ref_name)
5151
return oid_ptr[]
5252
end

base/libgit2/strarray.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
function StrArrayStruct{T<:AbstractString}(strs::T...)
44
strcount = length(strs)
5-
map(s->Base.unsafe_convert(Cstring, String(s)), strs) # check for null-strings
5+
for s in strs
6+
if Base.containsnul(s)
7+
throw("embedded NULs are not allowed in C strings: $(repr(s))")
8+
end
9+
end
610
sa_strings = convert(Ptr{Cstring}, Libc.malloc(sizeof(Cstring) * strcount))
711
for i=1:strcount
812
len = length(strs[i])

base/loading.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ function _require_from_serialized(node::Int, mod::Symbol, path_to_try::String, t
171171
end
172172
elseif node == myid()
173173
myid() == 1 && recompile_stale(mod, path_to_try)
174-
restored = ccall(:jl_restore_incremental, Any, (Ptr{UInt8},), path_to_try)
174+
restored = ccall(:jl_restore_incremental, Any, (Cstring,), path_to_try)
175175
else
176176
content = remotecall_fetch(open, node, read, path_to_try)
177177
restored = _include_from_serialized(content)
@@ -378,8 +378,8 @@ end
378378
# remote/parallel load
379379

380380
include_string(txt::String, fname::String) =
381-
ccall(:jl_load_file_string, Any, (Ptr{UInt8},Csize_t,Ptr{UInt8},Csize_t),
382-
txt, sizeof(txt), fname, sizeof(fname))
381+
ccall(:jl_load_file_string, Any, (Ptr{UInt8},Csize_t,Cstring),
382+
txt, sizeof(txt), fname)
383383

384384
include_string(txt::AbstractString, fname::AbstractString="string") =
385385
include_string(String(txt), String(fname))

base/precompile.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,7 @@ precompile(Libc.TmStruct, (Float64,))
154154
precompile(Base.VersionNumber, (Int, Int, Int, Tuple{}, Tuple{String}))
155155
precompile(Base._atexit, ())
156156
precompile(Base._deleteat!, (Array{UInt8, 1}, Int, Int))
157-
precompile(Base._deleteat_beg!, (Array{UInt8, 1}, Int, Int))
158-
precompile(Base._deleteat_end!, (Array{UInt8, 1}, Int, Int))
159-
precompile(Base._growat_beg!, (Array{UInt8, 1}, Int, Int))
160-
precompile(Base._growat_end!, (Array{UInt8, 1}, Int, Int))
157+
precompile(Base._growat!, (Array{UInt8, 1}, Int, Int))
161158
precompile(Base._setindex!, (Base.Dict{Symbol, Any}, Base.LineEdit.Prompt, Symbol, Int))
162159
precompile(Base._setindex!, (Dict{Any, Any}, Base.LineEdit.PromptState, Base.LineEdit.Prompt, Int))
163160
precompile(Base._setindex!, (Dict{Any, Any}, Bool, WeakRef, Int))

base/process.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ function _jl_spawn(cmd, argv, loop::Ptr{Void}, pp::Process,
310310
proc = Libc.malloc(_sizeof_uv_process)
311311
disassociate_julia_struct(proc)
312312
error = ccall(:jl_spawn, Int32,
313-
(Ptr{UInt8}, Ptr{Ptr{UInt8}}, Ptr{Void}, Ptr{Void}, Any, Int32,
314-
Ptr{Void}, Int32, Ptr{Void}, Int32, Ptr{Void}, Int32, Ptr{Ptr{UInt8}}, Ptr{UInt8}, Ptr{Void}),
313+
(Cstring, Ptr{Cstring}, Ptr{Void}, Ptr{Void}, Any, Int32,
314+
Ptr{Void}, Int32, Ptr{Void}, Int32, Ptr{Void}, Int32, Ptr{Cstring}, Cstring, Ptr{Void}),
315315
cmd, argv, loop, proc, pp, uvtype(in),
316316
uvhandle(in), uvtype(out), uvhandle(out), uvtype(err), uvhandle(err),
317317
pp.cmd.flags, pp.cmd.env === nothing ? C_NULL : pp.cmd.env, isempty(pp.cmd.dir) ? C_NULL : pp.cmd.dir,

base/refpointer.jl

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# This file is a part of Julia. License is MIT: http://julialang.org/license
22

3+
# C NUL-terminated string pointers; these can be used in ccall
4+
# instead of Ptr{Cchar} and Ptr{Cwchar_t}, respectively, to enforce
5+
# a check for embedded NUL chars in the string (to avoid silent truncation).
6+
if Int === Int64
7+
bitstype 64 Cstring
8+
bitstype 64 Cwstring
9+
else
10+
bitstype 32 Cstring
11+
bitstype 32 Cwstring
12+
end
13+
314
### General Methods for Ref{T} type
415

516
eltype{T}(x::Type{Ref{T}}) = T
@@ -62,10 +73,10 @@ end
6273
unsafe_convert{T}(::Type{Ptr{Void}}, b::RefArray{T}) = convert(Ptr{Void}, unsafe_convert(Ptr{T}, b))
6374

6475
# convert Arrays to pointer arrays for ccall
65-
function (::Type{Ref{P}}){P<:Ptr,T<:Ptr}(a::Array{T}) # Ref{P<:Ptr}(a::Array{T<:Ptr})
76+
function (::Type{Ref{P}}){P<:Union{Ptr,Cwstring,Cstring},T<:Union{Ptr,Cwstring,Cstring}}(a::Array{T}) # Ref{P<:Ptr}(a::Array{T<:Ptr})
6677
return RefArray(a) # effectively a no-op
6778
end
68-
function (::Type{Ref{P}}){P<:Ptr,T}(a::Array{T}) # Ref{P<:Ptr}(a::Array)
79+
function (::Type{Ref{P}}){P<:Union{Ptr,Cwstring,Cstring},T}(a::Array{T}) # Ref{P<:Ptr}(a::Array)
6980
if (!isbits(T) && T <: eltype(P))
7081
# this Array already has the right memory layout for the requested Ref
7182
return RefArray(a,1,false) # root something, so that this function is type-stable
@@ -82,7 +93,7 @@ function (::Type{Ref{P}}){P<:Ptr,T}(a::Array{T}) # Ref{P<:Ptr}(a::Array)
8293
end
8394
end
8495
cconvert{P<:Ptr,T<:Ptr}(::Union{Type{Ptr{P}},Type{Ref{P}}}, a::Array{T}) = a
85-
cconvert{P<:Ptr}(::Union{Type{Ptr{P}},Type{Ref{P}}}, a::Array) = Ref{P}(a)
96+
cconvert{P<:Union{Ptr,Cwstring,Cstring}}(::Union{Type{Ptr{P}},Type{Ref{P}}}, a::Array) = Ref{P}(a)
8697

8798
###
8899

0 commit comments

Comments
 (0)