diff --git a/Makefile b/Makefile index abc545139af35..cfc439578b8a6 100644 --- a/Makefile +++ b/Makefile @@ -562,7 +562,14 @@ ifneq (,$(filter $(ARCH), i386 i486 i586 i686)) $(JLDOWNLOAD) http://downloads.sourceforge.net/sevenzip/7z920.exe && \ 7z x -y 7z920.exe 7z.exe 7z.dll && \ ../contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_13.2 \ - "mingw32-libgfortran3 mingw32-libquadmath0 mingw32-libstdc++6 mingw32-libgcc_s_sjlj1 mingw32-libssp0 mingw32-libexpat1 mingw32-zlib1" && \ + "mingw32-libexpat1 mingw32-zlib1" && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw32-libgfortran3-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw32-libquadmath0-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw32-libstdc++6-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw32-libgcc_s_sjlj1-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw32-libssp0-5.3.0-1.1.noarch.rpm && \ + for i in *.rpm; do 7z x -y $$i; done && \ + for i in *.cpio; do 7z x -y $$i; done && \ cp usr/i686-w64-mingw32/sys-root/mingw/bin/*.dll . && \ $(JLDOWNLOAD) PortableGit.7z https://github.com/git-for-windows/git/releases/download/v2.6.1.windows.1/PortableGit-2.6.1-32-bit.7z.exe else ifeq ($(ARCH),x86_64) @@ -572,7 +579,14 @@ else ifeq ($(ARCH),x86_64) mv _7z.dll 7z.dll && \ mv _7z.exe 7z.exe && \ ../contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win64/openSUSE_13.2 \ - "mingw64-libgfortran3 mingw64-libquadmath0 mingw64-libstdc++6 mingw64-libgcc_s_seh1 mingw64-libssp0 mingw64-libexpat1 mingw64-zlib1" && \ + "mingw64-libexpat1 mingw64-zlib1" && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw64-libgfortran3-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw64-libquadmath0-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw64-libstdc++6-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw64-libgcc_s_seh1-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://juliacache.s3.amazonaws.com/mingw64-libssp0-5.3.0-1.1.noarch.rpm && \ + for i in *.rpm; do 7z x -y $$i; done && \ + for i in *.cpio; do 7z x -y $$i; done && \ cp usr/x86_64-w64-mingw32/sys-root/mingw/bin/*.dll . && \ $(JLDOWNLOAD) PortableGit.7z https://github.com/git-for-windows/git/releases/download/v2.6.1.windows.1/PortableGit-2.6.1-64-bit.7z.exe else diff --git a/base/Terminals.jl b/base/Terminals.jl index 1499c38ce6ef8..8dea2541f58b4 100644 --- a/base/Terminals.jl +++ b/base/Terminals.jl @@ -201,7 +201,14 @@ start_reading(t::UnixTerminal) = start_reading(t.in_stream) stop_reading(t::UnixTerminal) = stop_reading(t.in_stream) eof(t::UnixTerminal) = eof(t.in_stream) -@unix_only hascolor(t::TTYTerminal) = (startswith(t.term_type, "xterm") || success(`tput setaf 0`)) +@unix_only function hascolor(t::TTYTerminal) + startswith(t.term_type, "xterm") && return true + try + return success(`tput setaf 0`) + catch + return false + end +end @windows_only hascolor(t::TTYTerminal) = true end # module diff --git a/base/dict.jl b/base/dict.jl index 22fee19569fb6..ccd8dcd726a70 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -495,15 +495,21 @@ function rehash!{K,V}(h::Dict{K,V}, newsz = length(h.keys)) vals = Array(V, newsz) count0 = h.count count = 0 + maxprobe = max(16, newsz>>6) for i = 1:sz if olds[i] == 0x1 k = oldk[i] v = oldv[i] - index = hashindex(k, newsz) + index0 = index = hashindex(k, newsz) while slots[index] != 0 index = (index & (newsz-1)) + 1 end + if index - index0 > maxprobe + # rare condition: new table size causes more grouping of keys than before + # see issue #15077 + return rehash!(h, newsz*2) + end slots[index] = 0x1 keys[index] = k vals[index] = v diff --git a/base/docs/helpdb.jl b/base/docs/helpdb.jl index 747f2b0ec8c8c..4b8202b69d824 100644 --- a/base/docs/helpdb.jl +++ b/base/docs/helpdb.jl @@ -4011,46 +4011,67 @@ Note that workers do not run a ``.juliarc.jl`` startup script, nor do they synch """ addprocs() -doc""" -```rst -.. addprocs(machines; tunnel=false, sshflags=``, max_parallel=10, exeflags=``) -> List of process identifiers +""" +``` +addprocs(machines; keyword_args...) -> List of process identifiers +``` -Add processes on remote machines via SSH. -Requires julia to be installed in the same location on each node, or to be available via a shared file system. +Add processes on remote machines via SSH. Requires julia to be installed in the same +location on each node, or to be available via a shared file system. -``machines`` is a vector of machine specifications. Worker are started for each specification. +`machines` is a vector of machine specifications. Worker are started for each specification. -A machine specification is either a string ``machine_spec`` or a tuple - ``(machine_spec, count)`` +A machine specification is either a string `machine_spec` or a tuple - `(machine_spec, count)`. -``machine_spec`` is a string of the form ``[user@]host[:port] [bind_addr[:port]]``. ``user`` defaults -to current user, ``port`` to the standard ssh port. If ``[bind_addr[:port]]`` is specified, other -workers will connect to this worker at the specified ``bind_addr`` and ``port``. +`machine_spec` is a string of the form `[user@]host[:port] [bind_addr[:port]]`. `user` defaults +to current user, `port` to the standard ssh port. If `[bind_addr[:port]]` is specified, other +workers will connect to this worker at the specified `bind_addr` and `port`. -``count`` is the number of workers to be launched on the specified host. If specified as ``:auto`` +`count` is the number of workers to be launched on the specified host. If specified as `:auto` it will launch as many workers as the number of cores on the specific host. Keyword arguments: -``tunnel`` : if ``true`` then SSH tunneling will be used to connect to the worker from the master process. +* `tunnel`: if `true` then SSH tunneling will be used to connect to the worker from the + master process. Default is `false`. + +* `sshflags`: specifies additional ssh options, e.g. + + sshflags=`-i /home/foo/bar.pem` + +* `max_parallel`: specifies the maximum number of workers connected to in parallel at a host. + Defaults to 10. + +* `dir`: specifies the working directory on the workers. Defaults to the host's current + directory (as found by `pwd()`) -``sshflags`` : specifies additional ssh options, e.g. :literal:`sshflags=\`-i /home/foo/bar.pem\`` . +* `exename`: name of the julia executable. Defaults to `"\$JULIA_HOME/julia"` or + `"\$JULIA_HOME/julia-debug"` as the case may be. -``max_parallel`` : specifies the maximum number of workers connected to in parallel at a host. Defaults to 10. +* `exeflags`: additional flags passed to the worker processes. -``dir`` : specifies the working directory on the workers. Defaults to the host's current directory (as found by ``pwd()``) +* `topology`: Specifies how the workers connect to each other. Sending a message + between unconnected workers results in an error. -``exename`` : name of the julia executable. Defaults to "$JULIA_HOME/julia" or "$JULIA_HOME/julia-debug" as the case may be. + + `topology=:all_to_all` : All processes are connected to each other. + This is the default. + + + `topology=:master_slave` : Only the driver process, i.e. pid 1 connects to the + workers. The workers do not connect to each other. + + + `topology=:custom` : The `launch` method of the cluster manager specifes the + connection topology via fields `ident` and `connect_idents` in + `WorkerConfig`. A worker with a cluster manager identity `ident` + will connect to all workers specified in `connect_idents`. -``exeflags`` : additional flags passed to the worker processes. Environment variables : If the master process fails to establish a connection with a newly launched worker within 60.0 seconds, the worker treats it a fatal situation and terminates. This timeout can be controlled via environment -variable ``JULIA_WORKER_TIMEOUT``. The value of ``JULIA_WORKER_TIMEOUT`` on the master process, specifies +variable `JULIA_WORKER_TIMEOUT`. The value of `JULIA_WORKER_TIMEOUT` on the master process, specifies the number of seconds a newly launched worker waits for connection establishment. -``` """ addprocs(machines) @@ -10606,15 +10627,6 @@ This is only needed if your module depends on a file that is not used via `inclu """ include_dependency -doc""" - __precompile__(isprecompilable::Bool=true) - -Specify whether the file calling this function is precompilable. If `isprecompilable` is `true`, then `__precompile__` throws an exception when the file is loaded by `using`/`import`/`require` *unless* the file is being precompiled, and in a module file it causes the module to be automatically precompiled when it is imported. Typically, `__precompile__()` should occur before the `module` declaration in the file, or better yet `VERSION >= v"0.4" && __precompile__()` in order to be backward-compatible with Julia 0.3. - -If a module or file is *not* safely precompilable, it should call `__precompile__(false)` in order to throw an error if Julia attempts to precompile it. -""" -__precompile__ - doc""" randn!([rng], A::Array{Float64,N}) @@ -11082,7 +11094,7 @@ DivideError doc""" AssertionError([msg]) -The asserted condition did not evalutate to `true`. +The asserted condition did not evaluate to `true`. Optional argument `msg` is a descriptive error string. """ AssertionError diff --git a/base/linalg/blas.jl b/base/linalg/blas.jl index f1f95019da610..4d258ab7ee6df 100644 --- a/base/linalg/blas.jl +++ b/base/linalg/blas.jl @@ -57,6 +57,7 @@ export const libblas = Base.libblas_name +const liblapack = Base.liblapack_name import ..LinAlg: BlasReal, BlasComplex, BlasFloat, BlasInt, DimensionMismatch, chksquare, axpy! @@ -239,10 +240,10 @@ function axpy!{T<:BlasFloat,Ta<:Number,Ti<:Integer}(alpha::Ta, x::Array{T}, rx:: throw(DimensionMismatch("ranges of differing lengths")) end if minimum(rx) < 1 || maximum(rx) > length(x) - throw(BoundsError("range out of bounds for x, of length $(length(x))")) + throw(ArgumentError("range out of bounds for x, of length $(length(x))")) end if minimum(ry) < 1 || maximum(ry) > length(y) - throw(BoundsError("range out of bounds for y, of length $(length(y))")) + throw(ArgumentError("range out of bounds for y, of length $(length(y))")) end axpy!(length(rx), convert(T, alpha), pointer(x)+(first(rx)-1)*sizeof(T), step(rx), pointer(y)+(first(ry)-1)*sizeof(T), step(ry)) y @@ -342,10 +343,10 @@ for (fname, elty) in ((:dgbmv_,:Float64), end ### symv -for (fname, elty) in ((:dsymv_,:Float64), - (:ssymv_,:Float32), - (:zsymv_,:Complex128), - (:csymv_,:Complex64)) +for (fname, elty, lib) in ((:dsymv_,:Float64,libblas), + (:ssymv_,:Float32,libblas), + (:zsymv_,:Complex128,liblapack), + (:csymv_,:Complex64,liblapack)) # Note that the complex symv are not BLAS but auiliary functions in LAPACK @eval begin # SUBROUTINE DSYMV(UPLO,N,ALPHA,A,LDA,X,INCX,BETA,Y,INCY) @@ -366,7 +367,7 @@ for (fname, elty) in ((:dsymv_,:Float64), if m != length(y) throw(DimensionMismatch("A has size $(size(A)), and y has length $(length(y))")) end - ccall(($(blasfunc(fname)), libblas), Void, + ccall(($(blasfunc(fname)), $lib), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}), @@ -565,17 +566,17 @@ for (fname, elty) in ((:dger_,:Float64), end ### syr -for (fname, elty) in ((:dsyr_,:Float64), - (:ssyr_,:Float32), - (:zsyr_,:Complex128), - (:csyr_,:Complex64)) +for (fname, elty, lib) in ((:dsyr_,:Float64,libblas), + (:ssyr_,:Float32,libblas), + (:zsyr_,:Complex128,liblapack), + (:csyr_,:Complex64,liblapack)) @eval begin function syr!(uplo::Char, α::$elty, x::StridedVector{$elty}, A::StridedMatrix{$elty}) n = chksquare(A) if length(x) != n throw(DimensionMismatch("A has size ($n,$n), x has length $(length(x))")) end - ccall(($(blasfunc(fname)), libblas), Void, + ccall(($(blasfunc(fname)), $lib), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &uplo, &n, &α, x, @@ -943,10 +944,10 @@ end # module function copy!{T<:BlasFloat,Ti<:Integer}(dest::Array{T}, rdest::Union{UnitRange{Ti},Range{Ti}}, src::Array{T}, rsrc::Union{UnitRange{Ti},Range{Ti}}) if minimum(rdest) < 1 || maximum(rdest) > length(dest) - throw(BoundsError("range out of bounds for dest, of length $(length(dest))")) + throw(ArgumentError("range out of bounds for dest, of length $(length(dest))")) end if minimum(rsrc) < 1 || maximum(rsrc) > length(src) - throw(BoundsError("range out of bounds for src, of length $(length(src))")) + throw(ArgumentError("range out of bounds for src, of length $(length(src))")) end if length(rdest) != length(rsrc) throw(DimensionMismatch("ranges must be of the same length")) diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index fe8579add387a..fe818649135e8 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -185,7 +185,7 @@ function getindex{T<:BlasFloat}(C::CholeskyPivoted{T}, d::Symbol) end show{T,S<:AbstractMatrix}(io::IO, C::Cholesky{T,S}) = - (println("$(typeof(C)) with factor:");show(io,C[:UL])) + (println(io, "$(typeof(C)) with factor:");show(io,C[:UL])) A_ldiv_B!{T<:BlasFloat,S<:AbstractMatrix}(C::Cholesky{T,S}, B::StridedVecOrMat{T}) = LAPACK.potrs!(C.uplo, C.factors, B) diff --git a/base/linalg/generic.jl b/base/linalg/generic.jl index dd26028b58b60..f4c32eacbd294 100644 --- a/base/linalg/generic.jl +++ b/base/linalg/generic.jl @@ -447,14 +447,12 @@ function axpy!(α, x::AbstractArray, y::AbstractArray) end function axpy!{Ti<:Integer,Tj<:Integer}(α, x::AbstractArray, rx::AbstractArray{Ti}, y::AbstractArray, ry::AbstractArray{Tj}) - if length(x) != length(y) - throw(DimensionMismatch("x has length $(length(x)), but y has length $(length(y))")) + if length(rx) != length(ry) + throw(DimensionMismatch("rx has length $(length(rx)), but ry has length $(length(ry))")) elseif minimum(rx) < 1 || maximum(rx) > length(x) throw(BoundsError(x, rx)) elseif minimum(ry) < 1 || maximum(ry) > length(y) throw(BoundsError(y, ry)) - elseif length(rx) != length(ry) - throw(ArgumentError("rx has length $(length(rx)), but ry has length $(length(ry))")) end for i = 1:length(rx) @inbounds y[ry[i]] += x[rx[i]]*α @@ -462,6 +460,7 @@ function axpy!{Ti<:Integer,Tj<:Integer}(α, x::AbstractArray, rx::AbstractArray{ y end + # Elementary reflection similar to LAPACK. The reflector is not Hermitian but ensures that tridiagonalization of Hermitian matrices become real. See lawn72 @inline function reflector!(x::AbstractVector) n = length(x) diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 79380e0c5597c..48a66fecb40e5 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -256,7 +256,7 @@ function syrk_wrapper!{T<:BlasFloat}(C::StridedMatrix{T}, tA::Char, A::StridedVe return matmul3x3!(C,tA,tAt,A,A) end - if stride(A, 1) == 1 && stride(A, 2) >= size(A, 1) + if stride(A, 1) == stride(C, 1) == 1 && stride(A, 2) >= size(A, 1) && stride(C, 2) >= size(C, 1) return copytri!(BLAS.syrk!('U', tA, one(T), A, zero(T), C), 'U') end return generic_matmatmul!(C, tA, tAt, A, A) @@ -287,7 +287,7 @@ function herk_wrapper!{T<:BlasReal}(C::Union{StridedMatrix{T}, StridedMatrix{Com # Result array does not need to be initialized as long as beta==0 # C = Array(T, mA, mA) - if stride(A, 1) == 1 && stride(A, 2) >= size(A, 1) + if stride(A, 1) == stride(C, 1) == 1 && stride(A, 2) >= size(A, 1) && stride(C, 2) >= size(C, 1) return copytri!(BLAS.herk!('U', tA, one(T), A, zero(T), C), 'U', true) end return generic_matmatmul!(C,tA, tAt, A, A) @@ -325,7 +325,7 @@ function gemm_wrapper!{T<:BlasFloat}(C::StridedVecOrMat{T}, tA::Char, tB::Char, return matmul3x3!(C,tA,tB,A,B) end - if stride(A, 1) == stride(B, 1) == 1 && stride(A, 2) >= size(A, 1) && stride(B, 2) >= size(B, 1) + if stride(A, 1) == stride(B, 1) == stride(C, 1) == 1 && stride(A, 2) >= size(A, 1) && stride(B, 2) >= size(B, 1) && stride(C, 2) >= size(C, 1) return BLAS.gemm!(tA, tB, one(T), A, B, zero(T), C) end generic_matmatmul!(C, tA, tB, A, B) @@ -434,11 +434,12 @@ const Cbuf = Array(UInt8, tilebufsize) function generic_matmatmul!{T,S,R}(C::AbstractMatrix{R}, tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S}) mA, nA = lapack_size(tA, A) mB, nB = lapack_size(tB, B) + mC, nC = size(C) - if mA == nA == nB == 2 + if mA == nA == mB == nB == mC == nC == 2 return matmul2x2!(C, tA, tB, A, B) end - if mA == nA == nB == 3 + if mA == nA == mB == nB == mC == nC == 3 return matmul3x3!(C, tA, tB, A, B) end _generic_matmatmul!(C, tA, tB, A, B) @@ -450,14 +451,14 @@ function _generic_matmatmul!{T,S,R}(C::AbstractVecOrMat{R}, tA, tB, A::AbstractV mA, nA = lapack_size(tA, A) mB, nB = lapack_size(tB, B) if mB != nA - throw(DimensionMismatch("matrix A has dimensions ($mA, $nB), matrix B has dimensions ($mB, $nB)")) + throw(DimensionMismatch("matrix A has dimensions ($mA,$nA), matrix B has dimensions ($mB,$nB)")) end if size(C,1) != mA || size(C,2) != nB - throw(DimensionMismatch("result C has dimensions $(size(C)), needs ($mA, $nB)")) + throw(DimensionMismatch("result C has dimensions $(size(C)), needs ($mA,$nB)")) end tile_size = 0 - if isbits(R) && isbits(T) && isbits(S) + if isbits(R) && isbits(T) && isbits(S) && (tA == 'N' || tB != 'N') tile_size = floor(Int,sqrt(tilebufsize/max(sizeof(R),sizeof(S),sizeof(T)))) end @inbounds begin diff --git a/base/linalg/tridiag.jl b/base/linalg/tridiag.jl index 6417d45351214..c503d9f4b4711 100644 --- a/base/linalg/tridiag.jl +++ b/base/linalg/tridiag.jl @@ -77,7 +77,7 @@ function diag{T}(M::SymTridiagonal{T}, n::Integer=0) elseif absn= v"0.4" && __precompile__()` in order to be backward-compatible with Julia 0.3. + +If a module or file is *not* safely precompilable, it should call `__precompile__(false)` in +order to throw an error if Julia attempts to precompile it. + +`__precompile__()` should *not* be used in a module unless all of its dependencies are also +using `__precompile__()`. Failure to do so can result in a runtime error when loading the module. +""" function __precompile__(isprecompilable::Bool=true) if myid() == 1 && isprecompilable != (0 != ccall(:jl_generating_output, Cint, ())) && !(isprecompilable && toplevel_load::Bool) diff --git a/base/markdown/render/plain.jl b/base/markdown/render/plain.jl index 7e6b40e64ab85..be279dab2394c 100644 --- a/base/markdown/render/plain.jl +++ b/base/markdown/render/plain.jl @@ -20,9 +20,12 @@ function plain{l}(io::IO, header::Header{l}) end function plain(io::IO, code::Code) - println(io, "```", code.language) + # If the code includes a fenced block this will break parsing, + # so it must be enclosed by a longer ````-sequence. + n = mapreduce(length, max, 2, matchall(r"^`+"m, code.code)) + 1 + println(io, "`" ^ n, code.language) println(io, code.code) - println(io, "```") + println(io, "`" ^ n) end function plain(io::IO, p::Paragraph) diff --git a/base/mmap.jl b/base/mmap.jl index d7c645af42e97..eb85a37ffca2b 100644 --- a/base/mmap.jl +++ b/base/mmap.jl @@ -123,7 +123,7 @@ function mmap{T,N}(io::IO, @windows_only begin name, readonly, create = settings(io) - szfile = convert(DWORD, len + offset) + szfile = convert(Csize_t, len + offset) readonly && szfile > filesize(io) && throw(ArgumentError("unable to increase file size to $szfile due to read-only permissions")) handle = create ? ccall(:CreateFileMappingW, stdcall, Ptr{Void}, (Cptrdiff_t, Ptr{Void}, DWORD, DWORD, DWORD, Cwstring), file_desc, C_NULL, readonly ? PAGE_READONLY : PAGE_READWRITE, szfile >> 32, szfile & typemax(UInt32), name) : diff --git a/base/replutil.jl b/base/replutil.jl index 3fc381fcbbc34..88fc4eeadf03f 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -199,11 +199,10 @@ end #Useful in Base submodule __init__ functions where STDERR isn't defined yet. function showerror_nostdio(err, msg::AbstractString) stderr_stream = ccall(:jl_stderr_stream, Ptr{Void}, ()) - ccall(:jl_printf, UInt, (Ptr{Void},Cstring), stderr_stream, msg) - ccall(:jl_printf, UInt, (Ptr{Void},Cstring), stderr_stream, ":\n") - ccall(:jl_static_show, UInt, (Ptr{Void},Ptr{Void}), stderr_stream, - pointer_from_objref(err)) - ccall(:jl_printf, UInt, (Ptr{Void},Cstring), stderr_stream, "\n") + ccall(:jl_printf, Cint, (Ptr{Void},Cstring), stderr_stream, msg) + ccall(:jl_printf, Cint, (Ptr{Void},Cstring), stderr_stream, ":\n") + ccall(:jl_static_show, Csize_t, (Ptr{Void},Any), stderr_stream, err) + ccall(:jl_printf, Cint, (Ptr{Void},Cstring), stderr_stream, "\n") end const UNSHOWN_METHODS = ObjectIdDict( diff --git a/base/show.jl b/base/show.jl index 68279acb7756d..96cd56cbaa2ed 100644 --- a/base/show.jl +++ b/base/show.jl @@ -333,6 +333,7 @@ is_expr(ex, head::Symbol) = (isa(ex, Expr) && (ex.head == head)) is_expr(ex, head::Symbol, n::Int) = is_expr(ex, head) && length(ex.args) == n is_linenumber(ex::LineNumberNode) = true +is_linenumber(ex::Expr) = (ex.head == :line) is_linenumber(ex) = false is_quoted(ex) = false @@ -379,7 +380,8 @@ end emphasize(io, str::AbstractString) = have_color ? print_with_color(:red, io, str) : print(io, uppercase(str)) -show_linenumber(io::IO, file, line) = print(io," # ", file,", line ",line,':') +show_linenumber(io::IO, line) = print(io," # line ",line,':') +show_linenumber(io::IO, line, file) = print(io," # ", file,", line ",line,':') # show a block, e g if/for/etc function show_block(io::IO, head, args::Vector, body, indent::Int) @@ -448,7 +450,7 @@ end ## AST printing ## show_unquoted(io::IO, sym::Symbol, ::Int, ::Int) = print(io, sym) -show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.file, ex.line) +show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.line, ex.file) show_unquoted(io::IO, ex::LabelNode, ::Int, ::Int) = print(io, ex.label, ": ") show_unquoted(io::IO, ex::GotoNode, ::Int, ::Int) = print(io, "goto ", ex.label) show_unquoted(io::IO, ex::TopNode, ::Int, ::Int) = print(io,"top(",ex.name,')') @@ -681,6 +683,9 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) print(io, "typealias ") show_list(io, args, ' ', indent) + elseif is(head, :line) && 1 <= nargs <= 2 + show_linenumber(io, args...) + elseif is(head, :if) && nargs == 3 # if/else show_block(io, "if", args[1], args[2], indent) show_block(io, "else", args[3], indent) diff --git a/base/socket.jl b/base/socket.jl index f80b5d6ff7c13..30192dfd42bea 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -454,7 +454,7 @@ end function setopt(sock::UDPSocket; multicast_loop = nothing, multicast_ttl=nothing, enable_broadcast=nothing, ttl=nothing) if sock.status == StatusUninit - error("Cannot set options on unitialized socket") + error("Cannot set options on uninitialized socket") end if multicast_loop !== nothing uv_error("multicast_loop",ccall(:uv_udp_set_multicast_loop,Cint,(Ptr{Void},Cint),sock.handle,multicast_loop) < 0) diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index 4fffad126b291..b561dbdfed6c3 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -808,13 +808,15 @@ get_perm(FC::FactorComponent) = get_perm(Factor(FC)) ######################### # Convertion/construction -function convert{T<:VTypes}(::Type{Dense}, A::VecOrMat{T}) +function convert(::Type{Dense}, A::VecOrMat) + T = promote_type(eltype(A), Float64) d = allocate_dense(size(A, 1), size(A, 2), stride(A, 2), T) s = unsafe_load(d.p) - unsafe_copy!(s.x, pointer(A), length(A)) + for i in eachindex(A) + unsafe_store!(s.x, A[i], i) + end d end -convert(::Type{Dense}, A::VecOrMat) = Dense(float(A)) convert(::Type{Dense}, A::Sparse) = sparse_to_dense(A) # This constructior assumes zero based colptr and rowval diff --git a/base/sparse/umfpack.jl b/base/sparse/umfpack.jl index bbd50bc316c7a..ff2fb0e623e4a 100644 --- a/base/sparse/umfpack.jl +++ b/base/sparse/umfpack.jl @@ -33,7 +33,7 @@ function umferror(status::Integer) elseif status==UMFPACK_ERROR_argument_missing throw(ArgumentError("a required argument to UMFPack is missing")) elseif status==UMFPACK_ERROR_n_nonpositive - throw(BoundsError("the number of rows or columns of the matrix must be greater than zero")) + throw(ArgumentError("the number of rows or columns of the matrix must be greater than zero")) elseif status==UMFPACK_ERROR_invalid_matrix throw(ArgumentError("invalid matrix")) elseif status==UMFPACK_ERROR_different_pattern diff --git a/base/stream.jl b/base/stream.jl index 8027d464f4c21..6ea50af41612e 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -51,8 +51,8 @@ end # A dict of all libuv handles that are being waited on somewhere in the system # and should thus not be garbage collected const uvhandles = ObjectIdDict() -preserve_handle(x) = uvhandles[x] = get(uvhandles,x,0)+1 -unpreserve_handle(x) = (v = uvhandles[x]; v == 1 ? pop!(uvhandles,x) : (uvhandles[x] = v-1); nothing) +preserve_handle(x) = uvhandles[x] = get(uvhandles,x,0)::Int+1 +unpreserve_handle(x) = (v = uvhandles[x]::Int; v == 1 ? pop!(uvhandles,x) : (uvhandles[x] = v-1); nothing) function stream_wait(x, c...) # for x::LibuvObject preserve_handle(x) @@ -88,8 +88,13 @@ end nb_available(s::LibuvStream) = nb_available(s.buffer) function eof(s::LibuvStream) + if isopen(s) # fast path + nb_available(s) > 0 && return false + else + return nb_available(s) <= 0 + end wait_readnb(s,1) - !isopen(s) && nb_available(s)<=0 + !isopen(s) && nb_available(s) <= 0 end const DEFAULT_READ_BUFFER_SZ = 10485760 # 10 MB @@ -334,6 +339,11 @@ function wait_connected(x::Union{LibuvStream, LibuvServer}) end function wait_readbyte(x::LibuvStream, c::UInt8) + if isopen(x) # fast path + search(x.buffer, c) > 0 && return + else + return + end preserve_handle(x) try while isopen(x) && search(x.buffer, c) <= 0 @@ -346,9 +356,15 @@ function wait_readbyte(x::LibuvStream, c::UInt8) end unpreserve_handle(x) end + nothing end function wait_readnb(x::LibuvStream, nb::Int) + if isopen(x) # fast path + nb_available(x.buffer) >= nb && return + else + return + end oldthrottle = x.throttle preserve_handle(x) try @@ -366,12 +382,14 @@ function wait_readnb(x::LibuvStream, nb::Int) end unpreserve_handle(x) end + nothing end function wait_close(x::Union{LibuvStream, LibuvServer}) if isopen(x) stream_wait(x, x.closenotify) end + nothing end function close(stream::Union{LibuvStream, LibuvServer}) @@ -897,7 +915,7 @@ function read!(s::LibuvStream, a::Array{UInt8, 1}) finally s.buffer = sbuf if !isempty(s.readnotify.waitq) - start_reading(x) # resume reading iff there are currently other read clients of the stream + start_reading(s) # resume reading iff there are currently other read clients of the stream end end end @@ -1197,17 +1215,17 @@ write(s::BufferStream, c::Char) = write(s, string(c)) function write{T}(s::BufferStream, a::Array{T}) rv=write(s.buffer, a) !(s.buffer_writes) && notify(s.r_c; all=true); - rv + return rv end function write(s::BufferStream, p::Ptr, nb::Integer) rv=write(s.buffer, p, nb) !(s.buffer_writes) && notify(s.r_c; all=true); - rv + return rv end -function eof(s::LibuvStream) +function eof(s::BufferStream) wait_readnb(s,1) - !isopen(s) && nb_available(s)<=0 + return !isopen(s) && nb_available(s)<=0 end # If buffer_writes is called, it will delay notifying waiters till a flush is called. diff --git a/contrib/build_sysimg.jl b/contrib/build_sysimg.jl index 93178d2a48b15..e31c72d354efb 100644 --- a/contrib/build_sysimg.jl +++ b/contrib/build_sysimg.jl @@ -1,13 +1,11 @@ #!/usr/bin/env julia # This file is a part of Julia. License is MIT: http://julialang.org/license -# Build a system image binary at sysimg_path.dlext. By default, put the system image -# next to libjulia (except on Windows, where it goes in $JULIA_HOME\..\lib\julia) -# Allow insertion of a userimg via userimg_path. If sysimg_path.dlext is currently loaded into memory, -# don't continue unless force is set to true. Allow targeting of a CPU architecture via cpu_target +# Build a system image binary at sysimg_path.dlext. Allow insertion of a userimg via +# userimg_path. If sysimg_path.dlext is currently loaded into memory, don't continue +# unless force is set to true. Allow targeting of a CPU architecture via cpu_target @unix_only function default_sysimg_path(debug=false) - joinpath(dirname(Libdl.dlpath(debug ? "libjulia-debug" : "libjulia")), - "julia", debug ? "sys-debug" : "sys") + splitext(Libdl.dlpath(debug ? "sys-debug" : "sys"))[1] end @windows_only function default_sysimg_path(debug=false) @@ -82,7 +80,7 @@ function build_sysimg(sysimg_path=nothing, cpu_target="native", userimg_path=not info("System image successfully built at $sysimg_path.ji") end - if !Base.samefile("$default_sysimg_path.ji", "$sysimg_path.ji") + if !Base.samefile("$(default_sysimg_path(debug)).ji", "$sysimg_path.ji") if Base.isfile("$sysimg_path.$(Libdl.dlext)") info("To run Julia with this image loaded, run: julia -J $sysimg_path.$(Libdl.dlext)") else @@ -151,13 +149,6 @@ function link_sysimg(sysimg_path=nothing, cc=find_system_compiler(), debug=false run(`$cc $FLAGS -o $sysimg_path.$(Libdl.dlext) $sysimg_path.o`) info("System image successfully built at $sysimg_path.$(Libdl.dlext)") - @windows_only begin - if convert(VersionNumber, Base.libllvm_version) < v"3.5.0" - LLVM_msg = "Building sys.dll on Windows against LLVM < 3.5.0 can cause incorrect backtraces!" - LLVM_msg *= " Delete generated sys.dll to avoid these problems" - warn( LLVM_msg ) - end - end end # When running this file as a script, try to do so with default values. If arguments are passed @@ -176,7 +167,7 @@ if !isinteractive() println(" build_sysimg.jl /usr/local/lib/julia/sys core2 ~/my_usrimg.jl --force") println() println(" Running this script with no arguments is equivalent to:") - println(" build_sysimg.jl $(default_sysimg_path) native") + println(" build_sysimg.jl $(default_sysimg_path()) native") return 0 end diff --git a/contrib/windows/juliarc.jl b/contrib/windows/juliarc.jl index f2eca8637eed9..0f04c6729f5cf 100644 --- a/contrib/windows/juliarc.jl +++ b/contrib/windows/juliarc.jl @@ -1,4 +1,2 @@ -# This file should contain site-specific commands to be executed on Julia startup -# Users should store their own personal commands in homedir(), in a file named .juliarc.jl - +# Set up environment for Julia Windows binary distribution ENV["PATH"] = JULIA_HOME*";"*joinpath(JULIA_HOME,"..","Git","bin")*";"*ENV["PATH"] diff --git a/deps/Makefile b/deps/Makefile index cc190264035bd..6cb73bead3106 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -633,7 +633,9 @@ endif # x86_64 endif # WINNT else ifeq ($(LLVM_VER),3.7.1) - cd llvm-$(LLVM_VER) && patch -p1 < ../llvm-3.7.1.patch && patch -p1 < ../llvm-3.7.1_2.patch + cd llvm-$(LLVM_VER) && patch -p1 < ../llvm-3.7.1.patch && \ + patch -p1 < ../llvm-3.7.1_2.patch && \ + patch -p1 < ../llvm-3.7.1_3.patch endif # LLVM_VER touch -c $@ @@ -1165,6 +1167,13 @@ install-atlas: $(ATLAS_OBJ_TARGET) ## Mac gfortran BLAS wrapper ## GFORTBLAS_FFLAGS = +ifeq ($(USE_BLAS64), 1) +ifeq ($(USEIFC),1) +GFORTBLAS_FFLAGS += -i8 +else +GFORTBLAS_FFLAGS += -fdefault-integer-8 +endif +endif ifeq ($(OS),Darwin) ifeq ($(USE_SYSTEM_BLAS),1) ifeq ($(USE_SYSTEM_LAPACK),0) @@ -1251,10 +1260,8 @@ ARPACK_FFLAGS = $(GFORTBLAS_FFLAGS) ARPACK_CFLAGS = ifeq ($(USE_BLAS64), 1) -ifeq ($(USEIFC),1) -ARPACK_FFLAGS += -i8 -else -ARPACK_FFLAGS += -fdefault-integer-8 +ARPACK_CFLAGS += -DBLASINT=int64_t +ifneq ($(USEIFC),1) ifeq ($(USE_SYSTEM_BLAS), 0) ifeq ($(OPENBLAS_SYMBOLSUFFIX), 64_) ARPACK_FFLAGS += -cpp -ffixed-line-length-none @@ -1588,7 +1595,7 @@ $(SUITESPARSE_OBJ_TARGET): $(SUITESPARSE_OBJ_SOURCE) $(INSTALL_NAME_CMD)libcamd.$(SHLIB_EXT) $(build_shlibdir)/libcamd.$(SHLIB_EXT) && \ $(CC) -shared $(WHOLE_ARCHIVE) libccolamd.a $(NO_WHOLE_ARCHIVE) -o $(build_shlibdir)/libccolamd.$(SHLIB_EXT) $(LDFLAGS) -L$(build_shlibdir) -lsuitesparseconfig $(RPATH_ORIGIN) && \ $(INSTALL_NAME_CMD)libccolamd.$(SHLIB_EXT) $(build_shlibdir)/libccolamd.$(SHLIB_EXT) && \ - $(CXX) -shared $(WHOLE_ARCHIVE) libcholmod.a $(NO_WHOLE_ARCHIVE) -o $(build_shlibdir)/libcholmod.$(SHLIB_EXT) $(LDFLAGS) -L$(build_shlibdir) -lcolamd -lamd -lcamd -lccolamd -lsuitesparseconfig $(LIBBLAS) $(RPATH_ORIGIN) && \ + $(CXX) -shared $(WHOLE_ARCHIVE) libcholmod.a $(NO_WHOLE_ARCHIVE) -o $(build_shlibdir)/libcholmod.$(SHLIB_EXT) $(LDFLAGS) -L$(build_shlibdir) -lcolamd -lamd -lcamd -lccolamd -lsuitesparseconfig $(LIBLAPACK) $(LIBBLAS) $(RPATH_ORIGIN) && \ $(INSTALL_NAME_CMD)libcholmod.$(SHLIB_EXT) $(build_shlibdir)/libcholmod.$(SHLIB_EXT) && \ $(CXX) -shared $(WHOLE_ARCHIVE) libumfpack.a $(NO_WHOLE_ARCHIVE) -o $(build_shlibdir)/libumfpack.$(SHLIB_EXT) $(LDFLAGS) -L$(build_shlibdir) -lcholmod -lcolamd -lamd -lsuitesparseconfig $(LIBBLAS) $(RPATH_ORIGIN) && \ $(INSTALL_NAME_CMD)libumfpack.$(SHLIB_EXT) $(build_shlibdir)/libumfpack.$(SHLIB_EXT) && \ diff --git a/deps/llvm-3.7.1_3.patch b/deps/llvm-3.7.1_3.patch new file mode 100644 index 0000000000000..c955da9a0e26b --- /dev/null +++ b/deps/llvm-3.7.1_3.patch @@ -0,0 +1,16 @@ +Index: /lib/Analysis/ScalarEvolutionExpander.cpp +=================================================================== +--- /lib/Analysis/ScalarEvolutionExpander.cpp ++++ /lib/Analysis/ScalarEvolutionExpander.cpp +@@ -1273,6 +1273,11 @@ + if (!SE.dominates(Step, L->getHeader())) { + PostLoopScale = Step; + Step = SE.getConstant(Normalized->getType(), 1); ++ if (!PostLoopOffset) { ++ // otherwise, Start is known to already be a constant zero ++ PostLoopOffset = Start; ++ Start = SE.getConstant(Normalized->getType(), 0); ++ } + Normalized = + cast(SE.getAddRecExpr( + Start, Step, Normalized->getLoop(), diff --git a/doc/devdocs/types.rst b/doc/devdocs/types.rst index 1310a2e2161d5..eac1913f4f70c 100644 --- a/doc/devdocs/types.rst +++ b/doc/devdocs/types.rst @@ -362,12 +362,12 @@ type: in getindex at ./essentials.jl:211 in show_delim_array at show.jl:229 in show at show.jl:257 - in anonymous at show.jl:1294 - in with_output_limit at ./show.jl:1271 - in showlimited at show.jl:1293 + in anonymous at show.jl:1299 + in with_output_limit at ./show.jl:1276 + in showlimited at show.jl:1298 in display at multimedia.jl:120 [inlined code] from multimedia.jl:151 - in display at multimedia.jl:162 + in display at multimedia.jl:163 (The error is triggered because the cache is pre-allocated to have length 8, but only the first two entries are populated.) diff --git a/doc/manual/calling-c-and-fortran-code.rst b/doc/manual/calling-c-and-fortran-code.rst index bbf770a3845e7..be01653736efe 100644 --- a/doc/manual/calling-c-and-fortran-code.rst +++ b/doc/manual/calling-c-and-fortran-code.rst @@ -39,7 +39,7 @@ functions in the Julia runtime, or functions in an application linked to Julia. By default, Fortran compilers `generate mangled names -`_ +`_ (for example, converting function names to lowercase or uppercase, often appending an underscore), and so to call a Fortran function via ``ccall`` you must pass the mangled identifier corresponding to the rule @@ -916,7 +916,7 @@ More About Callbacks -------------------- For more details on how to pass callbacks to C libraries, see this -`blog post `_. +`blog post `_. C++ --- diff --git a/doc/manual/embedding.rst b/doc/manual/embedding.rst index e36f700a4adc6..4e7bd23d231cd 100644 --- a/doc/manual/embedding.rst +++ b/doc/manual/embedding.rst @@ -35,7 +35,9 @@ We start with a simple C program that initializes Julia and calls some Julia cod In order to build this program you have to put the path to the Julia header into the include path and link against ``libjulia``. For instance, when Julia is installed to ``$JULIA_DIR``, one can compile the above test program ``test.c`` with ``gcc`` using:: - gcc -o test -fPIC -I$JULIA_DIR/include/julia -L$JULIA_DIR/usr/lib test.c -ljulia + gcc -o test -fPIC -I$JULIA_DIR/include/julia -L$JULIA_DIR/lib/julia test.c -ljulia $JULIA_DIR/lib/julia/libstdc++.so.6 + +Then if the environment variable ``JULIA_HOME`` is set to ``$JULIA_DIR/bin``, the output ``test`` program can be executed. Alternatively, look at the ``embedding.c`` program in the Julia source tree in the ``examples/`` folder. The file ``ui/repl.c`` program is another simple example of how to set ``jl_options`` options while linking against ``libjulia``. diff --git a/doc/manual/faq.rst b/doc/manual/faq.rst index dce33384c7523..123e073b12b17 100644 --- a/doc/manual/faq.rst +++ b/doc/manual/faq.rst @@ -447,306 +447,6 @@ in the future, we could consider defaulting to checked integer arithmetic in Julia, but for now, we have to live with the possibility of overflow. -.. _man-abstract-fields: - -How do "abstract" or ambiguous fields in types interact with the compiler? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Types can be declared without specifying the types of their fields: - -.. doctest:: - - julia> type MyAmbiguousType - a - end - -This allows ``a`` to be of any type. This can often be useful, but it -does have a downside: for objects of type ``MyAmbiguousType``, the -compiler will not be able to generate high-performance code. The -reason is that the compiler uses the types of objects, not their -values, to determine how to build code. Unfortunately, very little can -be inferred about an object of type ``MyAmbiguousType``: - -.. doctest:: - - julia> b = MyAmbiguousType("Hello") - MyAmbiguousType("Hello") - - julia> c = MyAmbiguousType(17) - MyAmbiguousType(17) - - julia> typeof(b) - MyAmbiguousType - - julia> typeof(c) - MyAmbiguousType - -``b`` and ``c`` have the same type, yet their underlying -representation of data in memory is very different. Even if you stored -just numeric values in field ``a``, the fact that the memory -representation of a ``UInt8`` differs from a ``Float64`` also means -that the CPU needs to handle them using two different kinds of -instructions. Since the required information is not available in the -type, such decisions have to be made at run-time. This slows -performance. - -You can do better by declaring the type of ``a``. Here, we are focused -on the case where ``a`` might be any one of several types, in which -case the natural solution is to use parameters. For example: - -.. doctest:: - - julia> type MyType{T<:AbstractFloat} - a::T - end - -This is a better choice than - -.. doctest:: - - julia> type MyStillAmbiguousType - a::AbstractFloat - end - -because the first version specifies the type of ``a`` from the type of -the wrapper object. For example: - -.. doctest:: - - julia> m = MyType(3.2) - MyType{Float64}(3.2) - - julia> t = MyStillAmbiguousType(3.2) - MyStillAmbiguousType(3.2) - - julia> typeof(m) - MyType{Float64} - - julia> typeof(t) - MyStillAmbiguousType - -The type of field ``a`` can be readily determined from the type of -``m``, but not from the type of ``t``. Indeed, in ``t`` it's possible -to change the type of field ``a``: - -.. doctest:: - - julia> typeof(t.a) - Float64 - - julia> t.a = 4.5f0 - 4.5f0 - - julia> typeof(t.a) - Float32 - -In contrast, once ``m`` is constructed, the type of ``m.a`` cannot -change: - -.. doctest:: - - julia> m.a = 4.5f0 - 4.5 - - julia> typeof(m.a) - Float64 - -The fact that the type of ``m.a`` is known from ``m``'s type---coupled -with the fact that its type cannot change mid-function---allows the -compiler to generate highly-optimized code for objects like ``m`` but -not for objects like ``t``. - -Of course, all of this is true only if we construct ``m`` with a -concrete type. We can break this by explicitly constructing it with -an abstract type: - -.. doctest:: - - julia> m = MyType{AbstractFloat}(3.2) - MyType{AbstractFloat}(3.2) - - julia> typeof(m.a) - Float64 - - julia> m.a = 4.5f0 - 4.5f0 - - julia> typeof(m.a) - Float32 - -For all practical purposes, such objects behave identically to those -of ``MyStillAmbiguousType``. - -It's quite instructive to compare the sheer amount code generated for -a simple function -:: - - func(m::MyType) = m.a+1 - -using -:: - - code_llvm(func,(MyType{Float64},)) - code_llvm(func,(MyType{AbstractFloat},)) - code_llvm(func,(MyType,)) - -For reasons of length the results are not shown here, but you may wish -to try this yourself. Because the type is fully-specified in the first -case, the compiler doesn't need to generate any code to resolve the -type at run-time. This results in shorter and faster code. - - -.. _man-abstract-container-type: - -How should I declare "abstract container type" fields? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The same best practices that apply in the `previous section -<#man-abstract-fields>`_ also work for container types: - -.. doctest:: - - julia> type MySimpleContainer{A<:AbstractVector} - a::A - end - - julia> type MyAmbiguousContainer{T} - a::AbstractVector{T} - end - -For example: - -.. doctest:: - - julia> c = MySimpleContainer(1:3); - - julia> typeof(c) - MySimpleContainer{UnitRange{Int64}} - - julia> c = MySimpleContainer([1:3;]); - - julia> typeof(c) - MySimpleContainer{Array{Int64,1}} - - julia> b = MyAmbiguousContainer(1:3); - - julia> typeof(b) - MyAmbiguousContainer{Int64} - - julia> b = MyAmbiguousContainer([1:3;]); - - julia> typeof(b) - MyAmbiguousContainer{Int64} - -For ``MySimpleContainer``, the object is fully-specified by its type -and parameters, so the compiler can generate optimized functions. In -most instances, this will probably suffice. - -While the compiler can now do its job perfectly well, there are cases -where *you* might wish that your code could do different things -depending on the *element type* of ``a``. Usually the best way to -achieve this is to wrap your specific operation (here, ``foo``) in a -separate function:: - - function sumfoo(c::MySimpleContainer) - s = 0 - for x in c.a - s += foo(x) - end - s - end - - foo(x::Integer) = x - foo(x::AbstractFloat) = round(x) - -This keeps things simple, while allowing the compiler to generate -optimized code in all cases. - -However, there are cases where you may need to declare different -versions of the outer function for different element types of -``a``. You could do it like this:: - - function myfun{T<:AbstractFloat}(c::MySimpleContainer{Vector{T}}) - ... - end - function myfun{T<:Integer}(c::MySimpleContainer{Vector{T}}) - ... - end - -This works fine for ``Vector{T}``, but we'd also have to write -explicit versions for ``UnitRange{T}`` or other abstract types. To -prevent such tedium, you can use two parameters in the declaration of -``MyContainer``:: - - type MyContainer{T, A<:AbstractVector} - a::A - end - MyContainer(v::AbstractVector) = MyContainer{eltype(v), typeof(v)}(v) - - julia> b = MyContainer(1.3:5); - - julia> typeof(b) - MyContainer{Float64,UnitRange{Float64}} - -Note the somewhat surprising fact that ``T`` doesn't appear in the -declaration of field ``a``, a point that we'll return to in a moment. -With this approach, one can write functions such as:: - - function myfunc{T<:Integer, A<:AbstractArray}(c::MyContainer{T,A}) - return c.a[1]+1 - end - # Note: because we can only define MyContainer for - # A<:AbstractArray, and any unspecified parameters are arbitrary, - # the previous could have been written more succinctly as - # function myfunc{T<:Integer}(c::MyContainer{T}) - - function myfunc{T<:AbstractFloat}(c::MyContainer{T}) - return c.a[1]+2 - end - - function myfunc{T<:Integer}(c::MyContainer{T,Vector{T}}) - return c.a[1]+3 - end - - julia> myfunc(MyContainer(1:3)) - 2 - - julia> myfunc(MyContainer(1.0:3)) - 3.0 - - julia> myfunc(MyContainer([1:3])) - 4 - -As you can see, with this approach it's possible to specialize on both -the element type ``T`` and the array type ``A``. - -However, there's one remaining hole: we haven't enforced that ``A`` -has element type ``T``, so it's perfectly possible to construct an -object like this:: - - julia> b = MyContainer{Int64, UnitRange{Float64}}(1.3:5); - - julia> typeof(b) - MyContainer{Int64,UnitRange{Float64}} - -To prevent this, we can add an inner constructor:: - - type MyBetterContainer{T<:Real, A<:AbstractVector} - a::A - - MyBetterContainer(v::AbstractVector{T}) = new(v) - end - MyBetterContainer(v::AbstractVector) = MyBetterContainer{eltype(v),typeof(v)}(v) - - - julia> b = MyBetterContainer(1.3:5); - - julia> typeof(b) - MyBetterContainer{Float64,UnitRange{Float64}} - - julia> b = MyBetterContainer{Int64, UnitRange{Float64}}(1.3:5); - ERROR: no method MyBetterContainer(UnitRange{Float64},) - -The inner constructor requires that the element type of ``A`` be ``T``. .. _faq-packages: diff --git a/doc/manual/functions.rst b/doc/manual/functions.rst index fb20e8fa967ba..98d5355001a61 100644 --- a/doc/manual/functions.rst +++ b/doc/manual/functions.rst @@ -476,25 +476,32 @@ Keyword argument default values are evaluated only when necessary left-to-right order. Therefore default expressions may refer to prior keyword arguments. +The types of keyword arguments can be made explicit as follows:: + + function f(;x::Int64=1) + ### + end + Extra keyword arguments can be collected using ``...``, as in varargs functions:: - function f(x; y=0, args...) + function f(x; y=0, kwargs...) ### end -Inside ``f``, ``args`` will be a collection of ``(key,value)`` tuples, +Inside ``f``, ``kwargs`` will be a collection of ``(key,value)`` tuples, where each ``key`` is a symbol. Such collections can be passed as keyword -arguments using a semicolon in a call, e.g. ``f(x, z=1; args...)``. +arguments using a semicolon in a call, e.g. ``f(x, z=1; kwargs...)``. Dictionaries can also be used for this purpose. -In addition, one can also pass ``(key,value)`` tuples, or any iterable +One can also pass ``(key,value)`` tuples, or any iterable expression (such as a ``=>`` pair) that can be assigned to such a tuple, explicitly after a semicolon. For example, ``plot(x, y; (:width,2))`` and ``plot(x, y; :width => 2)`` are equivalent to ``plot(x, y, width=2)``. This is useful in situations where the keyword name is computed at runtime. +.. _man-evaluation-scope-default-values: Evaluation Scope of Default Values ---------------------------------- diff --git a/doc/manual/getting-started.rst b/doc/manual/getting-started.rst index c4d6e4bf68560..9aea497549146 100644 --- a/doc/manual/getting-started.rst +++ b/doc/manual/getting-started.rst @@ -163,6 +163,6 @@ help new users get started with Julia: - `Learn Julia in a few minutes `_ - `Tutorial for Homer Reid's numerical analysis class `_ - `An introductory presentation `_ -- `Videos from the Julia tutorial at MIT `_ +- `Videos from the Julia tutorial at MIT `_ - `Forio Julia Tutorials `_ diff --git a/doc/manual/modules.rst b/doc/manual/modules.rst index 6b988f50d80ad..af2f4ed425f11 100644 --- a/doc/manual/modules.rst +++ b/doc/manual/modules.rst @@ -6,12 +6,14 @@ .. index:: module, baremodule, using, import, export, importall -Modules in Julia are separate global variable workspaces. They are -delimited syntactically, inside ``module Name ... end``. Modules allow -you to create top-level definitions without worrying about name conflicts -when your code is used together with somebody else's. Within a module, you -can control which names from other modules are visible (via importing), -and specify which of your names are intended to be public (via exporting). +Modules in Julia are separate variable workspaces, i.e. they introduce +a new global scope. They are delimited syntactically, inside ``module +Name ... end``. Modules allow you to create top-level definitions (aka +global variables) without worrying about name conflicts when your code +is used together with somebody else's. Within a module, you can +control which names from other modules are visible (via importing), +and specify which of your names are intended to be public (via +exporting). The following example demonstrates the major features of modules. It is not meant to be run, but is shown for illustrative purposes:: @@ -282,6 +284,10 @@ therein. If you know that it is *not* safe to precompile your module throw an error (and thereby prevent the module from being imported by any other precompiled module). +``__precompile__()`` should *not* be used in a module unless all of its +dependencies are also using ``__precompile__()``. Failure to do so can result +in a runtime error when loading the module. + In order to make your module work with precompilation, however, you may need to change your module to explicitly separate any initialization steps that must occur at *runtime* from steps that can @@ -354,7 +360,7 @@ not a standalone interpreter that also generates compiled code. Other known potential failure scenarios include: -1. Global counters (for example, for attempting to unique identifying objects) +1. Global counters (for example, for attempting to uniquely identify objects) Consider the following code snippet:: type UniquedById diff --git a/doc/manual/noteworthy-differences.rst b/doc/manual/noteworthy-differences.rst index f023327995f79..c53d037f1d92a 100644 --- a/doc/manual/noteworthy-differences.rst +++ b/doc/manual/noteworthy-differences.rst @@ -98,6 +98,8 @@ some noteworthy differences that may trip up Julia users accustomed to MATLAB: ``ans`` is not set when Julia code is run in non-interactive mode. - Julia's ``type``\ s do not support dynamically adding fields at runtime, unlike MATLAB's ``class``\ es. Instead, use a :obj:`Dict`. +- In Julia each module has its own global scope/namespace, whereas in + Matlab there is just one global scope. Noteworthy differences from R ----------------------------- diff --git a/doc/manual/performance-tips.rst b/doc/manual/performance-tips.rst index df033f3182fc8..bc15e0d489ab5 100644 --- a/doc/manual/performance-tips.rst +++ b/doc/manual/performance-tips.rst @@ -166,6 +166,10 @@ that can be manipulated efficiently. See also the discussion under :ref:`man-parametric-types`. + + + + Type declarations ----------------- @@ -176,25 +180,312 @@ arguments, local variables, and expressions. However, there are a few specific instances where declarations are helpful. -Declare specific types for fields of composite types -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. _man-abstract-fields: + +Avoid fields with abstract type +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Types can be declared without specifying the types of their fields: + +.. doctest:: + + julia> type MyAmbiguousType + a + end + +This allows ``a`` to be of any type. This can often be useful, but it +does have a downside: for objects of type ``MyAmbiguousType``, the +compiler will not be able to generate high-performance code. The +reason is that the compiler uses the types of objects, not their +values, to determine how to build code. Unfortunately, very little can +be inferred about an object of type ``MyAmbiguousType``: + +.. doctest:: + + julia> b = MyAmbiguousType("Hello") + MyAmbiguousType("Hello") + + julia> c = MyAmbiguousType(17) + MyAmbiguousType(17) + + julia> typeof(b) + MyAmbiguousType + + julia> typeof(c) + MyAmbiguousType + +``b`` and ``c`` have the same type, yet their underlying +representation of data in memory is very different. Even if you stored +just numeric values in field ``a``, the fact that the memory +representation of a ``UInt8`` differs from a ``Float64`` also means +that the CPU needs to handle them using two different kinds of +instructions. Since the required information is not available in the +type, such decisions have to be made at run-time. This slows +performance. + +You can do better by declaring the type of ``a``. Here, we are focused +on the case where ``a`` might be any one of several types, in which +case the natural solution is to use parameters. For example: + +.. doctest:: + + julia> type MyType{T<:AbstractFloat} + a::T + end + +This is a better choice than + +.. doctest:: + + julia> type MyStillAmbiguousType + a::AbstractFloat + end + +because the first version specifies the type of ``a`` from the type of +the wrapper object. For example: + +.. doctest:: + + julia> m = MyType(3.2) + MyType{Float64}(3.2) + + julia> t = MyStillAmbiguousType(3.2) + MyStillAmbiguousType(3.2) + + julia> typeof(m) + MyType{Float64} + + julia> typeof(t) + MyStillAmbiguousType + +The type of field ``a`` can be readily determined from the type of +``m``, but not from the type of ``t``. Indeed, in ``t`` it's possible +to change the type of field ``a``: + +.. doctest:: + + julia> typeof(t.a) + Float64 + + julia> t.a = 4.5f0 + 4.5f0 + + julia> typeof(t.a) + Float32 + +In contrast, once ``m`` is constructed, the type of ``m.a`` cannot +change: + +.. doctest:: + + julia> m.a = 4.5f0 + 4.5 + + julia> typeof(m.a) + Float64 + +The fact that the type of ``m.a`` is known from ``m``'s type---coupled +with the fact that its type cannot change mid-function---allows the +compiler to generate highly-optimized code for objects like ``m`` but +not for objects like ``t``. + +Of course, all of this is true only if we construct ``m`` with a +concrete type. We can break this by explicitly constructing it with +an abstract type: + +.. doctest:: + + julia> m = MyType{AbstractFloat}(3.2) + MyType{AbstractFloat}(3.2) + + julia> typeof(m.a) + Float64 + + julia> m.a = 4.5f0 + 4.5f0 + + julia> typeof(m.a) + Float32 + +For all practical purposes, such objects behave identically to those +of ``MyStillAmbiguousType``. + +It's quite instructive to compare the sheer amount code generated for +a simple function +:: + + func(m::MyType) = m.a+1 + +using +:: + + code_llvm(func,(MyType{Float64},)) + code_llvm(func,(MyType{AbstractFloat},)) + code_llvm(func,(MyType,)) + +For reasons of length the results are not shown here, but you may wish +to try this yourself. Because the type is fully-specified in the first +case, the compiler doesn't need to generate any code to resolve the +type at run-time. This results in shorter and faster code. + + +.. _man-abstract-container-type: + +Avoid fields with abstract containers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The same best practices also work for container types: + +.. doctest:: + + julia> type MySimpleContainer{A<:AbstractVector} + a::A + end + + julia> type MyAmbiguousContainer{T} + a::AbstractVector{T} + end + +For example: + +.. doctest:: + + julia> c = MySimpleContainer(1:3); + + julia> typeof(c) + MySimpleContainer{UnitRange{Int64}} + + julia> c = MySimpleContainer([1:3;]); + + julia> typeof(c) + MySimpleContainer{Array{Int64,1}} + + julia> b = MyAmbiguousContainer(1:3); + + julia> typeof(b) + MyAmbiguousContainer{Int64} + + julia> b = MyAmbiguousContainer([1:3;]); + + julia> typeof(b) + MyAmbiguousContainer{Int64} + +For ``MySimpleContainer``, the object is fully-specified by its type +and parameters, so the compiler can generate optimized functions. In +most instances, this will probably suffice. + +While the compiler can now do its job perfectly well, there are cases +where *you* might wish that your code could do different things +depending on the *element type* of ``a``. Usually the best way to +achieve this is to wrap your specific operation (here, ``foo``) in a +separate function:: + + function sumfoo(c::MySimpleContainer) + s = 0 + for x in c.a + s += foo(x) + end + s + end + + foo(x::Integer) = x + foo(x::AbstractFloat) = round(x) + +This keeps things simple, while allowing the compiler to generate +optimized code in all cases. -Given a user-defined type like the following:: +However, there are cases where you may need to declare different +versions of the outer function for different element types of +``a``. You could do it like this:: - type Foo - field + function myfun{T<:AbstractFloat}(c::MySimpleContainer{Vector{T}}) + ... + end + function myfun{T<:Integer}(c::MySimpleContainer{Vector{T}}) + ... + end + +This works fine for ``Vector{T}``, but we'd also have to write +explicit versions for ``UnitRange{T}`` or other abstract types. To +prevent such tedium, you can use two parameters in the declaration of +``MyContainer``:: + + type MyContainer{T, A<:AbstractVector} + a::A + end + MyContainer(v::AbstractVector) = MyContainer{eltype(v), typeof(v)}(v) + + julia> b = MyContainer(1.3:5); + + julia> typeof(b) + MyContainer{Float64,UnitRange{Float64}} + +Note the somewhat surprising fact that ``T`` doesn't appear in the +declaration of field ``a``, a point that we'll return to in a moment. +With this approach, one can write functions such as:: + + function myfunc{T<:Integer, A<:AbstractArray}(c::MyContainer{T,A}) + return c.a[1]+1 + end + # Note: because we can only define MyContainer for + # A<:AbstractArray, and any unspecified parameters are arbitrary, + # the previous could have been written more succinctly as + # function myfunc{T<:Integer}(c::MyContainer{T}) + + function myfunc{T<:AbstractFloat}(c::MyContainer{T}) + return c.a[1]+2 + end + + function myfunc{T<:Integer}(c::MyContainer{T,Vector{T}}) + return c.a[1]+3 end -the compiler will not generally know the type of ``foo.field``, since it -might be modified at any time to refer to a value of a different type. -It will help to declare the most specific type possible, such as -``field::Float64`` or ``field::Array{Int64,1}``. + julia> myfunc(MyContainer(1:3)) + 2 + + julia> myfunc(MyContainer(1.0:3)) + 3.0 + + julia> myfunc(MyContainer([1:3])) + 4 + +As you can see, with this approach it's possible to specialize on both +the element type ``T`` and the array type ``A``. + +However, there's one remaining hole: we haven't enforced that ``A`` +has element type ``T``, so it's perfectly possible to construct an +object like this:: + + julia> b = MyContainer{Int64, UnitRange{Float64}}(1.3:5); + + julia> typeof(b) + MyContainer{Int64,UnitRange{Float64}} + +To prevent this, we can add an inner constructor:: + + type MyBetterContainer{T<:Real, A<:AbstractVector} + a::A + + MyBetterContainer(v::AbstractVector{T}) = new(v) + end + MyBetterContainer(v::AbstractVector) = MyBetterContainer{eltype(v),typeof(v)}(v) + + + julia> b = MyBetterContainer(1.3:5); + + julia> typeof(b) + MyBetterContainer{Float64,UnitRange{Float64}} + + julia> b = MyBetterContainer{Int64, UnitRange{Float64}}(1.3:5); + ERROR: no method MyBetterContainer(UnitRange{Float64},) + +The inner constructor requires that the element type of ``A`` be ``T``. Annotate values taken from untyped locations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is often convenient to work with data structures that may contain -values of any type, such as the original ``Foo`` type above, or cell +values of any type, such as cell arrays (arrays of type ``Array{Any}``). But, if you're using one of these structures and happen to know the type of an element, it helps to share this knowledge with the compiler:: diff --git a/doc/manual/variables-and-scoping.rst b/doc/manual/variables-and-scoping.rst index 6d36b09f55d5e..1579f83346c1c 100644 --- a/doc/manual/variables-and-scoping.rst +++ b/doc/manual/variables-and-scoping.rst @@ -6,234 +6,386 @@ Scope of Variables ******************** -The *scope* of a variable is the region of code within which a variable -is visible. Variable scoping helps avoid variable naming conflicts. The -concept is intuitive: two functions can both have arguments called ``x`` -without the two ``x``'s referring to the same thing. Similarly there are -many other cases where different blocks of code can use the same name -without referring to the same thing. The rules for when the same -variable name does or doesn't refer to the same thing are called scope -rules; this section spells them out in detail. +The *scope* of a variable is the region of code within which a +variable is visible. Variable scoping helps avoid variable naming +conflicts. The concept is intuitive: two functions can both have +arguments called ``x`` without the two ``x``'s referring to the same +thing. Similarly there are many other cases where different blocks of +code can use the same name without referring to the same thing. The +rules for when the same variable name does or doesn't refer to the +same thing are called scope rules; this section spells them out in +detail. Certain constructs in the language introduce *scope blocks*, which are regions of code that are eligible to be the scope of some set of -variables. The scope of a variable cannot be an arbitrary set of source -lines; instead, it will always line up with one of these blocks. -The constructs introducing such blocks are: - -- ``function`` bodies (:ref:`either syntax `) -- ``while`` loops -- ``for`` loops -- ``try`` blocks -- ``catch`` blocks -- ``finally`` blocks -- ``let`` blocks -- ``type`` blocks. - -Notably missing from this list are -:ref:`begin blocks ` and :ref:`if blocks `, which do -*not* introduce new scope blocks. - -Certain constructs introduce new variables into the current innermost -scope. When a variable is introduced into a scope, it is also inherited -by all inner scopes unless one of those inner scopes explicitly -overrides it. +variables. The scope of a variable cannot be an arbitrary set of +source lines; instead, it will always line up with one of these +blocks. There are two main types of scopes in Julia, *global scope* +and *local scope*, the latter can be nested. The constructs +introducing scope blocks are: + +.. _man-scope-table: + ++--------------------------------+----------------------------------------------------------------------------------+ +| Scope name | block/construct introducing this kind of scope | ++================================+==================================================================================+ +| :ref:`global ` | | module, baremodule, at interactive prompt (REPL) | ++--------------------------------+------------------------------+---------------------------------------------------+ +| :ref:`local ` | :ref:`soft ` | | for, while, list-comprehensions, | +| | | try-catch-finally, let | +| +------------------------------+---------------------------------------------------+ +| | :ref:`hard ` | | functions (either syntax, anonymous & do-blocks)| +| | | | type, immutable, macro | ++--------------------------------+------------------------------+---------------------------------------------------+ + +Notably missing from this table are :ref:`begin blocks +` and :ref:`if blocks +`, which do *not* introduce new scope +blocks. All three types of scopes follow somewhat different rules +which will be explained below as well as some extra rules for +certain blocks. Julia uses `lexical scoping `_, meaning that a function's scope does not inherit from its caller's scope, but from the scope in which the function was defined. -For example, in the following code the ``x`` inside ``foo`` is found -in the global scope (and if no global variable ``x`` existed, an -undefined variable error would be raised):: +For example, in the following code the ``x`` inside ``foo`` is refers +to the ``x`` in the global scope of its module ``Bar``:: - function foo() - x + module Bar + x = 1 + foo() = x end - function bar() - x = 1 - foo() - end +and not a ``x`` in the scope where ``foo`` is used:: - x = 2 + julia> import Bar - julia> bar() - 2 + julia> x = -1; -If ``foo`` is instead defined inside ``bar``, then it accesses -the local ``x`` present in that function:: + julia> Bar.foo() + 1 - function bar() - function foo() - x - end - x = 1 - foo() +Thus *lexical scope* means that the scope of variables can be inferred +from the source code alone. + +.. _man-global: + +Global Scope +------------ + +*Each module introduces a new global scope*, separate from the global +scope of all other modules; there is no all-encompassing global scope. +Modules can introduce variables of other modules into their scope +through the :ref:`using or import ` statements or through +qualified access using the dot-notation, i.e. each module is a +so-called *namespace*. Note that variable bindings can only be +changed within their global scope and not from an outside module. :: + + module A + a = 1 # a global in A's scope end - x = 2 + module B + # b = a # would error as B's global scope is separate from A's + module C + c = 2 + end + b = C.c # can access the namespace of a nested global scope + # through a qualified access + import A # makes module A available + d = A.a + # A.a = 2 # would error with: "ERROR: cannot assign variables in other modules" + end - julia> bar() - 1 +Note that the interactive prompt (aka REPL) is in the global scope of +the module ``Main``. -The constructs that introduce new variables into the current scope -are as follows: - -- A declaration ``local x`` or ``const x`` introduces a new local variable. -- A declaration ``global x`` makes ``x`` in the current scope and inner - scopes refer to the global variable of that name. -- A function's arguments are introduced as new local variables into the - function's body scope. -- An assignment ``x = y`` introduces a new local variable ``x`` only if - ``x`` is neither declared global nor introduced as local - by any enclosing scope before *or after* the current line of code. - -In the following example, there is only one ``x`` assigned both inside -and outside the ``for`` loop:: - - function foo(n) - x = 0 - for i = 1:n - x = x + 1 - end - x +.. _man-local-scope: + +Local Scope +----------- + +A new local scope is introduced by most code-blocks, see above +:ref:`table ` for a complete list. A local scope +*usually* inherits all the variables from its parent scope, both for +reading and writing. There are two subtypes of local scopes, hard and +soft, with slightly different rules concerning what variables are +inherited. Unlike global scopes, local scopes are not namespaces, +thus variables in an inner scope cannot be retrieved from the parent +scope through some sort of qualified access. + +The following rules and examples pertain to both hard and soft local +scopes. A newly introduced variable in a local scope does not +back-propagate to its parent scope. For example, here the ``z`` is not +introduced into the top-level scope:: + + for i=1:10 + z = i end - julia> foo(10) - 10 + julia> z + ERROR: UndefVarError: z not defined + +(Note, in this and all following examples it is assumed that their +top-level is a global scope with a clean workspace, for instance a +newly started REPL.) -In the next example, the loop has a separate ``x`` and the function -always returns zero:: +Inside a local scope a variable can be forced to be a local variable +using the ``local`` keyword:: - function foo(n) - x = 0 - for i = 1:n + x = 0 + for i=1:10 local x - x = i - end - x + x = i + 1 end - julia> foo(10) + julia> x 0 -In this example, an ``x`` exists only inside the loop, and the function -encounters an undefined variable error on its last line (unless there is -a global variable ``x``):: +Inside a local scope a new global variable can be defined using the +keyword ``global``:: - function foo(n) - for i = 1:n - x = i - end - x + for i=1:10 + global z + z = i end - julia> foo(10) - in foo: x not defined - -A variable that is not assigned to or otherwise introduced locally -defaults to global, so this function would return the value of the -global ``x`` if there were such a variable, or produce an error if no such -global existed. As a consequence, the only way to assign to a global -variable inside a non-top-level scope is to explicitly declare the -variable as global within some scope, since otherwise the assignment -would introduce a new local rather than assigning to the global. This -rule works out well in practice, since the vast majority of variables -assigned inside functions are intended to be local variables, and using -global variables should be the exception rather than the rule, -and assigning new values to them even more so. - -One last example shows that an outer assignment introducing ``x`` need -not come before an inner usage:: - - function foo(n) - f = y -> n + x + y - x = 1 - f(2) + julia> z + 10 + +.. + However, there is no keyword to introduce a new local variable into a + parent local scope. + +The location of both the ``local`` and ``global`` keywords within the +scope block is irrelevant. The following is equivalent to the last +example (although stylistically worse):: + + for i=1:10 + z = i + global z end - julia> foo(10) - 13 + julia> z + 10 -This behavior may seem slightly odd for a normal variable, but allows -for named functions — which are just normal variables holding function -objects — to be used before they are defined. This allows functions to -be defined in whatever order is intuitive and convenient, rather than -forcing bottom up ordering or requiring forward declarations, both of -which one typically sees in C programs. As an example, here is an -inefficient, mutually recursive way to test if positive integers are -even or odd:: +Multiple global or local definitions can be on one line and can also +be paired with assignments:: - even(n) = n == 0 ? true : odd(n-1) - odd(n) = n == 0 ? false : even(n-1) + for i=1:10 + global x=i, y, z + local a=4, b , c=1 + end - julia> even(3) - false - julia> odd(3) - true +.. _man-soft-scope: -Julia provides built-in, efficient functions to test for oddness and evenness -called :func:`iseven` and :func:`isodd` so the above definitions should only be -taken as examples. +Soft Local Scope +^^^^^^^^^^^^^^^^ -Since functions can be used before they are defined, as long as they are -defined by the time they are actually called, no syntax for forward -declarations is necessary, and definitions can be ordered arbitrarily. + In a soft local scope, all variables are inherited from its parent + scope unless a variable is specifically marked with the keyword + ``local``. -At the interactive prompt, variable scope works the same way as anywhere -else. The prompt behaves as if there is scope block wrapped around -everything you type, except that this scope block is identified with the -global scope. This is especially evident in the case of assignments: +Soft local scopes are introduced by for-loops, while-loops, +list-comprehensions, try-catch-finally-blocks, and let-blocks. There +are some extra rules for :ref:`let-blocks ` and for +:ref:`for-loops and list-comprehensions `. -.. doctest:: +In the following example the ``x`` and ``y`` refer always to the same +variables as the soft local scope inherits both read and write +variables:: - julia> for i = 1:1; y = 10; end + x,y = 0, 1 + for i = 1:10 + x = i + y + 1 + end - julia> y - ERROR: UndefVarError: y not defined + julia> x + 11 - julia> y = 0 - 0 +Within soft scopes, the `global` keyword is never necessary, although +allowed. The only case when it would change the semantics is +(currently) a syntax error:: - julia> for i = 1:1; y = 10; end + let + local x = 2 + let + global x = 3 + end + end - julia> y - 10 + # ERROR: syntax: `global x`: x is local variable in the enclosing scope -In the former case, ``y`` only exists inside of the ``for`` loop. In the -latter case, an outer ``y`` has been introduced and so is inherited -within the loop. Due to the special identification of the prompt's scope -block with the global scope, it is not necessary to declare ``global y`` -inside the loop. However, in code not entered into the interactive -prompt this declaration would be necessary in order to modify a global -variable. +.. _man-hard-scope: -Multiple variables can be declared global using the following syntax:: +Hard Local Scope +^^^^^^^^^^^^^^^^ +Hard local scopes are introduced by function definitions (in all their +forms), type & immutable-blocks and macro-definitions. + + In a hard local scope, all variables are inherited from its parent + scope unless: + + - an assignment would result in a modified *global* variable, or + - a variable is specifically marked with the keyword ``local``. + +Thus global variables are only inherited for reading but not for +writing:: + + x,y = 1,2 function foo() - global x=1, y="bar", z=3 + x = 2 # assignment introduces a new local + return x + y # y refers to the global end julia> foo() - 3 + 4 julia> x 1 - julia> y - "bar" +An explicit ``global`` is needed to assign to a global variable:: - julia> z - 3 + x = 1 + function foo() + global x = 2 + end + foo() + + julia> x + 2 + +Note that *nested functions* can behave differently to functions +defined in the global scope as they can modify their parent scope's +*local* variables:: + + x,y = 1,2 + function foo() + x = 2 # introduces a new local + function bar() + x = 10 # modifies the parent's x + return x+y # y is global + end + return bar() + x # 12 + 10 (x is modified in call of bar()) + end + + julia> foo() + 22 # (x,y unchanged) + +The distinction between inheriting global and local variables for +assignment can lead to some slight differences between functions +defined in local vs. global scopes. Consider the modification of the +last example by moving ``bar`` to the global scope:: + + x,y = 1,2 + function bar() + x = 10 # local + return x+y + end + function foo() + x = 2 # local + return bar() + x # 12 + 2 (x is not modified) + end + + julia> foo() + 14 # as x is not modified anymore. + # (x,y unchanged) + +Note that above subtlety does not pertain to type and macro +definitions as they can only appear at the global scope. +There are special scoping rules concerning the evaluation of default +and keyword function arguments which are described in the +:ref:`Function section `. + + +An assignment introducing a variable used inside a function, type or +macro definition need not come before its inner usage: + +.. doctest:: + + julia> f = y -> x + y + (anonymous function) + + julia> f(3) + ERROR: UndefVarError: x not defined + in anonymous at none:1 + + julia> x = 1 + 1 + + julia> f(3) + 4 + +This behavior may seem slightly odd for a normal variable, but allows +for named functions — which are just normal variables holding function +objects — to be used before they are defined. This allows functions to +be defined in whatever order is intuitive and convenient, rather than +forcing bottom up ordering or requiring forward declarations, as long +as they are defined by the time they are actually called. As an +example, here is an inefficient, mutually recursive way to test if +positive integers are even or odd:: + + even(n) = n == 0 ? true : odd(n-1) + odd(n) = n == 0 ? false : even(n-1) + + julia> even(3) + false + + julia> odd(3) + true + +Julia provides built-in, efficient functions to test for oddness and evenness +called :func:`iseven` and :func:`isodd` so the above definitions should only be +taken as examples. + +Hard vs. Soft Local Scope +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Blocks which introduce a soft local scope, such as loops, are +generally used to manipulate the variables in their parent scope. +Thus their default is to fully access all variables in their parent +scope. + +Conversely, the code inside blocks which introduce a hard local scope +(function, type and macro definitions) can be executed at any place in +a program. Remotely changing the state of global variables in other +modules should be done with care and thus this is an opt-in feature +requiring the ``global`` keyword. + +The reason to allow *modifying local* variables of parent scopes in +nested functions is to allow constructing `closures +`_ +which have a private state, for instance the ``state`` variable in the +following example:: + + let + state = 0 + global counter + counter() = state += 1 + end + + julia> counter() + 1 + + julia> counter() + 2 + +See also the closures in the examples in the next two sections. + +.. _man-let-blocks: + +Let Blocks +^^^^^^^^^^ -The ``let`` statement provides a different way to introduce variables. Unlike assignments to local variables, ``let`` statements allocate new -variable bindings each time they run. An assignment modifies an existing -value location, and ``let`` creates new locations. This difference is -usually not important, and is only detectable in the case of variables -that outlive their scope via closures. The ``let`` syntax accepts a -comma-separated series of assignments and variable names:: +variable bindings each time they run. An assignment modifies an +existing value location, and ``let`` creates new locations. This +difference is usually not important, and is only detectable in the +case of variables that outlive their scope via closures. The ``let`` +syntax accepts a comma-separated series of assignments and variable +names:: let var1 = value1, var2, var3 = value3 code @@ -245,7 +397,7 @@ has been introduced. Therefore it makes sense to write something like ``let x = x`` since the two ``x`` variables are distinct and have separate storage. Here is an example where the behavior of ``let`` is needed:: - Fs = cell(2) + Fs = Array(Any,2) i = 1 while i <= 2 Fs[i] = ()->i @@ -263,7 +415,7 @@ However, it is always the same variable ``i``, so the two closures behave identically. We can use ``let`` to create a new binding for ``i``:: - Fs = cell(2) + Fs = Array(Any,2) i = 1 while i <= 2 let i = i @@ -296,15 +448,21 @@ block without creating any new bindings: Since ``let`` introduces a new scope block, the inner local ``x`` is a different variable than the outer local ``x``. + +.. _man-for-loops-scope: + For Loops and Comprehensions ----------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + -``for`` loops and :ref:`comprehensions ` have a special -additional behavior: any new variables introduced in their body scopes are -freshly allocated for each loop iteration. Therefore these constructs are -similar to ``while`` loops with ``let`` blocks inside:: +``for`` loops and :ref:`comprehensions ` have the +following behavior: any new variables introduced in their body scopes +are freshly allocated for each loop iteration. This is in contrast to +``while`` loops which reuse the variables for all +iterations. Therefore these constructs are similar to ``while`` loops +with ``let`` blocks inside:: - Fs = cell(2) + Fs = Array(Any,2) for i = 1:2 Fs[i] = ()->i end @@ -315,7 +473,7 @@ similar to ``while`` loops with ``let`` blocks inside:: julia> Fs[2]() 2 -``for`` loops will reuse existing variables for iteration:: +``for`` loops will reuse existing variables for its iteration variable:: i = 0 for i = 1:3 diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 250c2edec02ad..60f734871edf3 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -142,6 +142,8 @@ Getting Around If a module or file is *not* safely precompilable, it should call ``__precompile__(false)`` in order to throw an error if Julia attempts to precompile it. + ``__precompile__()`` should *not* be used in a module unless all of its dependencies are also using ``__precompile__()``\ . Failure to do so can result in a runtime error when loading the module. + .. function:: include(path::AbstractString) .. Docstring generated from Julia source @@ -1033,7 +1035,7 @@ Errors .. Docstring generated from Julia source - The asserted condition did not evalutate to ``true``\ . Optional argument ``msg`` is a descriptive error string. + The asserted condition did not evaluate to ``true``\ . Optional argument ``msg`` is a descriptive error string. .. function:: BoundsError([a],[i]) diff --git a/doc/stdlib/parallel.rst b/doc/stdlib/parallel.rst index 505ec2398638b..890e3d244e292 100644 --- a/doc/stdlib/parallel.rst +++ b/doc/stdlib/parallel.rst @@ -159,45 +159,49 @@ General Parallel Computing Support Note that workers do not run a ``.juliarc.jl`` startup script, nor do they synchronize their global state (such as global variables, new method definitions, and loaded modules) with any of the other running processes. -.. function:: addprocs(machines; tunnel=false, sshflags=``, max_parallel=10, exeflags=``) -> List of process identifiers +.. function:: addprocs(machines; keyword_args...) -> List of process identifiers .. Docstring generated from Julia source - Add processes on remote machines via SSH. - Requires julia to be installed in the same location on each node, or to be available via a shared file system. + Add processes on remote machines via SSH. Requires julia to be installed in the same location on each node, or to be available via a shared file system. ``machines`` is a vector of machine specifications. Worker are started for each specification. - A machine specification is either a string ``machine_spec`` or a tuple - ``(machine_spec, count)`` + A machine specification is either a string ``machine_spec`` or a tuple - ``(machine_spec, count)``\ . - ``machine_spec`` is a string of the form ``[user@]host[:port] [bind_addr[:port]]``. ``user`` defaults - to current user, ``port`` to the standard ssh port. If ``[bind_addr[:port]]`` is specified, other - workers will connect to this worker at the specified ``bind_addr`` and ``port``. - - ``count`` is the number of workers to be launched on the specified host. If specified as ``:auto`` - it will launch as many workers as the number of cores on the specific host. + ``machine_spec`` is a string of the form ``[user@]host[:port] [bind_addr[:port]]``\ . ``user`` defaults to current user, ``port`` to the standard ssh port. If ``[bind_addr[:port]]`` is specified, other workers will connect to this worker at the specified ``bind_addr`` and ``port``\ . + ``count`` is the number of workers to be launched on the specified host. If specified as ``:auto`` it will launch as many workers as the number of cores on the specific host. Keyword arguments: - ``tunnel`` : if ``true`` then SSH tunneling will be used to connect to the worker from the master process. + * ``tunnel``\ : if ``true`` then SSH tunneling will be used to connect to the worker from the master process. Default is ``false``\ . + + * ``sshflags``\ : specifies additional ssh options, e.g. + + .. code-block:: julia + + sshflags=`-i /home/foo/bar.pem` + + * ``max_parallel``\ : specifies the maximum number of workers connected to in parallel at a host. Defaults to 10. + + * ``dir``\ : specifies the working directory on the workers. Defaults to the host's current directory (as found by ``pwd()``\ ) + + * ``exename``\ : name of the julia executable. Defaults to ``"$JULIA_HOME/julia"`` or ``"$JULIA_HOME/julia-debug"`` as the case may be. - ``sshflags`` : specifies additional ssh options, e.g. :literal:`sshflags=\`-i /home/foo/bar.pem\`` . + * ``exeflags``\ : additional flags passed to the worker processes. - ``max_parallel`` : specifies the maximum number of workers connected to in parallel at a host. Defaults to 10. + * ``topology``\ : Specifies how the workers connect to each other. Sending a message between unconnected workers results in an error. - ``dir`` : specifies the working directory on the workers. Defaults to the host's current directory (as found by ``pwd()``) + * ``topology=:all_to_all`` : All processes are connected to each other. This is the default. - ``exename`` : name of the julia executable. Defaults to "$JULIA_HOME/julia" or "$JULIA_HOME/julia-debug" as the case may be. + * ``topology=:master_slave`` : Only the driver process, i.e. pid 1 connects to the workers. The workers do not connect to each other. - ``exeflags`` : additional flags passed to the worker processes. + * ``topology=:custom`` : The ``launch`` method of the cluster manager specifes the connection topology via fields ``ident`` and ``connect_idents`` in ``WorkerConfig``\ . A worker with a cluster manager identity ``ident`` will connect to all workers specified in ``connect_idents``\ . Environment variables : - If the master process fails to establish a connection with a newly launched worker within 60.0 seconds, - the worker treats it a fatal situation and terminates. This timeout can be controlled via environment - variable ``JULIA_WORKER_TIMEOUT``. The value of ``JULIA_WORKER_TIMEOUT`` on the master process, specifies - the number of seconds a newly launched worker waits for connection establishment. + If the master process fails to establish a connection with a newly launched worker within 60.0 seconds, the worker treats it a fatal situation and terminates. This timeout can be controlled via environment variable ``JULIA_WORKER_TIMEOUT``\ . The value of ``JULIA_WORKER_TIMEOUT`` on the master process, specifies the number of seconds a newly launched worker waits for connection establishment. .. function:: addprocs(manager::ClusterManager; kwargs...) -> List of process identifiers diff --git a/src/abi_aarch64.cpp b/src/abi_aarch64.cpp new file mode 100644 index 0000000000000..b71328d274e9b --- /dev/null +++ b/src/abi_aarch64.cpp @@ -0,0 +1,336 @@ +// This file is a part of Julia. License is MIT: http://julialang.org/license + +//===----------------------------------------------------------------------===// +// +// The ABI implementation used for AArch64 targets. +// +//===----------------------------------------------------------------------===// +// +// The Procedure Call Standard can be found here: +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf +// +//===----------------------------------------------------------------------===// + +namespace { + +typedef bool AbiState; +static const AbiState default_abi_state = 0; + +static Type *get_llvm_fptype(jl_datatype_t *dt) +{ + // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) + if (dt->mutabl || jl_datatype_nfields(dt) != 0) + return NULL; + Type *lltype; + // Check size first since it's cheaper. + switch (dt->size) { + case 2: + lltype = T_float16; + break; + case 4: + lltype = T_float32; + break; + case 8: + lltype = T_float64; + break; + case 16: + lltype = T_float128; + break; + default: + return NULL; + } + return jl_is_floattype((jl_value_t*)dt) ? lltype : NULL; +} + +struct ElementType { + Type *type; + size_t sz; + ElementType() : type(nullptr), sz(0) {}; +}; + +// Whether a type is a homogeneous floating-point aggregates (HFA) or a +// homogeneous short-vector aggregates (HVA). Returns the element type. +// We only handle HFA of HP, SP, DP and QP here since these are the only ones we +// have (no vectors). +// An Homogeneous Aggregate is a Composite Type where all of the Fundamental +// Data Types of the members that compose the type are the same. +// Note that it is the fundamental types that are important and not the member +// types. +static bool isHFAorHVA(jl_datatype_t *dt, size_t dsz, size_t &nele, ElementType &ele) +{ + // Assume: + // dt is a pointerfree type, (all members are isbits) + // dsz == dt->size > 0 + // 0 <= nele <= 3 + + // We ignore zero sized member here. This isn't really consistent with + // GCC for zero-sized array members. GCC seems to treat structs with + // zero sized array members as non-HFA and non-HVA. Clang (3.7 and 3.8) + // handles this slightly differently. + // Ref https://llvm.org/bugs/show_bug.cgi?id=26162 + while (size_t nfields = jl_datatype_nfields(dt)) { + // For composite types, find the first non zero sized member + size_t i; + size_t fieldsz; + for (i = 0;i < nfields;i++) { + if ((fieldsz = jl_field_size(dt, i))) { + break; + } + } + assert(i < nfields); + // If there's only one non zero sized member, try again on this member + if (fieldsz == dsz) { + dt = (jl_datatype_t*)jl_field_type(dt, i); + continue; + } + // Otherwise, process each members + for (;i < nfields;i++) { + size_t fieldsz = jl_field_size(dt, i); + if (fieldsz == 0) + continue; + jl_datatype_t *fieldtype = (jl_datatype_t*)jl_field_type(dt, i); + // Check element count. + // This needs to be done after the zero size member check + if (nele > 3 || !isHFAorHVA(fieldtype, fieldsz, nele, ele)) { + return false; + } + } + return true; + } + // For bitstypes + if (ele.sz && dsz != ele.sz) + return false; + Type *new_type = get_llvm_fptype(dt); + if (new_type && (!ele.type || ele.type == new_type)) { + ele.type = new_type; + ele.sz = dsz; + nele++; + return true; + } + return false; +} + +static Type *isHFAorHVA(jl_datatype_t *dt, size_t &nele) +{ + // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) + + // An Homogeneous Floating-point Aggregate (HFA) is an Homogeneous Aggregate + // with a Fundamental Data Type that is a Floating-Point type and at most + // four uniquely addressable members. + // An Homogeneous Short-Vector Aggregate (HVA) is an Homogeneous Aggregate + // with a Fundamental Data Type that is a Short-Vector type and at most four + // uniquely addressable members. + // Maximum HFA and HVA size is 64 bytes (4 x fp128 or 16bytes vector) + size_t dsz = dt->size; + if (dsz > 64 || !dt->pointerfree || dt->haspadding) + return NULL; + nele = 0; + ElementType eltype; + if (isHFAorHVA(dt, dsz, nele, eltype)) + return eltype.type; + return NULL; +} + +void needPassByRef(AbiState*, jl_value_t *ty, bool *byRef, bool*) +{ + // Assume jl_is_datatype(ty) && !jl_is_abstracttype(ty) + jl_datatype_t *dt = (jl_datatype_t*)ty; + // B.2 + // If the argument type is an HFA or an HVA, then the argument is used + // unmodified. + size_t size; + if (isHFAorHVA(dt, size)) + return; + // B.3 + // If the argument type is a Composite Type that is larger than 16 bytes, + // then the argument is copied to memory allocated by the caller and the + // argument is replaced by a pointer to the copy. + // We only check for the total size and not whether it is a composite type + // since there's no corresponding C type and we just treat such large + // bitstype as a composite type of the right size. + *byRef = dt->size > 16; + // B.4 + // If the argument type is a Composite Type then the size of the argument + // is rounded up to the nearest multiple of 8 bytes. +} + +bool need_private_copy(jl_value_t*, bool) +{ + return false; +} + +// Determine which kind of register the argument will be passed in and +// if the argument has to be passed on stack (including by reference). +// +// If the argument should be passed in SIMD and floating-point registers, +// we may need to rewrite the argument types to [n x ftype]. +// If the argument should be passed in general purpose registers, we may need +// to rewrite the argument types to [n x i64]. +// +// If the argument has to be passed on stack, we need to use sret. +// +// All the out parameters should be default to `false`. +static Type *classify_arg(jl_value_t *ty, bool *fpreg, bool *onstack, + size_t *rewrite_len) +{ + // Assume jl_is_datatype(ty) && !jl_is_abstracttype(ty) + jl_datatype_t *dt = (jl_datatype_t*)ty; + + // Based on section 5.4 C of the Procedure Call Standard + // C.1 + // If the argument is a Half-, Single-, Double- or Quad- precision + // Floating-point or Short Vector Type and the NSRN is less than 8, then + // the argument is allocated to the least significant bits of register + // v[NSRN]. The NSRN is incremented by one. The argument has now been + // allocated. + // Note that this is missing QP float as well as short vector types since we + // don't really have those types. + if (get_llvm_fptype(dt)) { + *fpreg = true; + return NULL; + } + + // C.2 + // If the argument is an HFA or an HVA and there are sufficient + // unallocated SIMD and Floating-point registers (NSRN + number of + // members <= 8), then the argument is allocated to SIMD and + // Floating-point Registers (with one register per member of the HFA + // or HVA). The NSRN is incremented by the number of registers used. + // The argument has now been allocated. + if (Type *eltype = isHFAorHVA(dt, *rewrite_len)) { + assert(*rewrite_len > 0 && *rewrite_len <= 4); + // HFA and HVA have <= 4 members + *fpreg = true; + // Rewrite to [n x eltype] where n is the number of fundamental types. + return eltype; + } + + // Check if the argument needs to be passed by reference. This should be + // done before starting step C but we do this here to avoid checking for + // HFA and HVA twice. We don't check whether it is a composite type. + // See `needPassByRef` above. + if (dt->size > 16) { + *onstack = true; + return NULL; + } + + // C.3 + // If the argument is an HFA or an HVA then the NSRN is set to 8 and the + // size of the argument is rounded up to the nearest multiple of 8 bytes. + // C.4 + // If the argument is an HFA, an HVA, a Quad-precision Floating-point or + // Short Vector Type then the NSAA is rounded up to the larger of 8 or + // the Natural Alignment of the argument’s type. + // C.5 + // If the argument is a Half- or Single- precision Floating Point type, + // then the size of the argument is set to 8 bytes. The effect is as if + // the argument had been copied to the least significant bits of a 64-bit + // register and the remaining bits filled with unspecified values. + // C.6 + // If the argument is an HFA, an HVA, a Half-, Single-, Double- or + // Quad- precision Floating-point or Short Vector Type, then the argument + // is copied to memory at the adjusted NSAA. The NSAA is incremented + // by the size of the argument. The argument has now been allocated. + // + // C.7 + // If the argument is an Integral or Pointer Type, the size of the + // argument is less than or equal to 8 bytes and the NGRN is less than 8, + // the argument is copied to the least significant bits in x[NGRN]. + // The NGRN is incremented by one. The argument has now been allocated. + // Here we treat any bitstype of the right size as integers or pointers + // This is needed for types like Cstring which should be treated as + // pointers. We don't need to worry about floating points here since they + // are handled above. + if (jl_is_immutable(dt) && jl_datatype_nfields(dt) == 0 && + (dt->size == 1 || dt->size == 2 || dt->size == 4 || + dt->size == 8 || dt->size == 16)) + return NULL; + + // C.8 + // If the argument has an alignment of 16 then the NGRN is rounded up to + // the next even number. + // C.9 + // If the argument is an Integral Type, the size of the argument is equal + // to 16 and the NGRN is less than 7, the argument is copied to x[NGRN] + // and x[NGRN+1]. x[NGRN] shall contain the lower addressed double-word + // of the memory representation of the argument. The NGRN is incremented + // by two. The argument has now been allocated. + // + // C.10 + // If the argument is a Composite Type and the size in double-words of + // the argument is not more than 8 minus NGRN, then the argument is + // copied into consecutive general-purpose registers, starting at x[NGRN]. + // The argument is passed as though it had been loaded into the registers + // from a double-word-aligned address with an appropriate sequence of LDR + // instructions loading consecutive registers from memory (the contents of + // any unused parts of the registers are unspecified by this standard). + // The NGRN is incremented by the number of registers used. The argument + // has now been allocated. + // We don't check for composite types here since the ones that have + // corresponding C types are already handled and we just treat the ones + // with weird size as a black box composite type. + // The type can fit in 8 x 8 bytes since it is handled by + // need_pass_by_ref otherwise. + // 0-size types (Void) won't be rewritten and that is what we want + assert(dt->size <= 16); // Should be pass by reference otherwise + *rewrite_len = (dt->size + 7) >> 3; + // Rewrite to [n x Int64] where n is the **size in dword** + return dt->size ? T_int64 : NULL; + + // C.11 + // The NGRN is set to 8. + // C.12 + // The NSAA is rounded up to the larger of 8 or the Natural Alignment + // of the argument’s type. + // C.13 + // If the argument is a composite type then the argument is copied to + // memory at the adjusted NSAA. The NSAA is incremented by the size of + // the argument. The argument has now been allocated. + // + // C.14 + // If the size of the argument is less than 8 bytes then the size of the + // argument is set to 8 bytes. The effect is as if the argument was + // copied to the least significant bits of a 64-bit register and the + // remaining bits filled with unspecified values. + // C.15 + // The argument is copied to memory at the adjusted NSAA. The NSAA is + // incremented by the size of the argument. The argument has now been + // allocated. + // +} + +bool use_sret(AbiState*, jl_value_t *ty) +{ + // Assume jl_is_datatype(ty) && !jl_is_abstracttype(ty) + // Section 5.5 + // If the type, T, of the result of a function is such that + // + // void func(T arg) + // + // would require that arg be passed as a value in a register (or set of + // registers) according to the rules in section 5.4 Parameter Passing, + // then the result is returned in the same registers as would be used for + // such an argument. + bool fpreg = false; + bool onstack = false; + size_t rewrite_len = 0; + classify_arg(ty, &fpreg, &onstack, &rewrite_len); + return onstack; +} + +Type *preferred_llvm_type(jl_value_t *ty, bool) +{ + if (!jl_is_datatype(ty) || jl_is_abstracttype(ty)) + return NULL; + jl_datatype_t *dt = (jl_datatype_t*)ty; + if (Type *fptype = get_llvm_fptype(dt)) + return fptype; + bool fpreg = false; + bool onstack = false; + size_t rewrite_len = 0; + if (Type *rewrite_ty = classify_arg(ty, &fpreg, &onstack, &rewrite_len)) + return ArrayType::get(rewrite_ty, rewrite_len); + return NULL; +} + +} diff --git a/src/abi_win32.cpp b/src/abi_win32.cpp index b7949d5aaa68a..aec0e42a336f8 100644 --- a/src/abi_win32.cpp +++ b/src/abi_win32.cpp @@ -42,34 +42,34 @@ AbiState default_abi_state = 0; bool use_sret(AbiState *state, jl_value_t *ty) { - if (!jl_is_datatype(ty) || jl_is_abstracttype(ty) || jl_is_cpointer_type(ty) || jl_is_array_type(ty)) - return false; - size_t size = jl_datatype_size(ty); - if (size <= 8) + // Assume jl_is_datatype(ty) && !jl_is_abstracttype(ty) + jl_datatype_t *dt = (jl_datatype_t*)ty; + // Use sret if the size of the argument is not one of 1, 2, 4, 8 bytes + // This covers the special case of Complex64 + size_t size = dt->size; + if (size == 1 || size == 2 || size == 4 || size == 8) return false; return true; } void needPassByRef(AbiState *state, jl_value_t *ty, bool *byRef, bool *inReg, bool *byRefAttr) { - if (!jl_is_datatype(ty) || jl_is_abstracttype(ty) || jl_is_cpointer_type(ty) || jl_is_array_type(ty)) - return; - size_t size = jl_datatype_size(ty); - if (size <= 8) - return; - *byRefAttr = *byRef = true; + // Assume jl_is_datatype(ty) && !jl_is_abstracttype(ty) + jl_datatype_t *dt = (jl_datatype_t*)ty; + // Use pass by reference for all structs + *byRefAttr = *byRef = dt->nfields > 0; } Type *preferred_llvm_type(jl_value_t *ty, bool isret) { - if (!isret) + // Arguments are either scalar or passed by value + if (!isret || !jl_is_datatype(ty) || jl_is_abstracttype(ty)) return NULL; - if (!jl_is_datatype(ty) || jl_is_abstracttype(ty) || jl_is_cpointer_type(ty) || jl_is_array_type(ty)) + jl_datatype_t *dt = (jl_datatype_t*)ty; + // rewrite integer sized (non-sret) struct to the corresponding integer + if (!dt->nfields || use_sret(NULL, ty)) return NULL; - size_t size = jl_datatype_size(ty); - if (size > 0 && size <= 8 && !jl_is_bitstype(ty)) - return Type::getIntNTy(getGlobalContext(), size*8); - return NULL; + return Type::getIntNTy(getGlobalContext(), dt->size * 8); } bool need_private_copy(jl_value_t *ty, bool byRef) diff --git a/src/array.c b/src/array.c index a798164ac089c..8d8a353786dda 100644 --- a/src/array.c +++ b/src/array.c @@ -685,6 +685,7 @@ void jl_array_sizehint(jl_array_t *a, size_t sz) void jl_array_grow_beg(jl_array_t *a, size_t inc) { + // For pointer array the memory grown should be zero'd if (inc == 0) return; // designed to handle the case of growing and shrinking at both ends if (a->isshared) array_try_unshare(a); @@ -705,12 +706,8 @@ void jl_array_grow_beg(jl_array_t *a, size_t inc) newlen = limit_overallocation(a, alen, newlen, 2*inc); size_t center = (newlen - (alen + inc))/2; array_resize_buffer(a, newlen, alen, center+inc); - char *newdata = (char*)a->data - (center+inc)*es; - if (a->ptrarray) { - memset(newdata, 0, (center+inc)*es); - } a->offset = center; - a->data = newdata + center*es; + a->data = (char*)a->data - incnb; } else { size_t center = (a->maxsize - (alen + inc))/2; @@ -720,6 +717,8 @@ void jl_array_grow_beg(jl_array_t *a, size_t inc) a->offset = center; } } + if (a->ptrarray) + memset((char*)a->data, 0, incnb); #ifdef STORE_ARRAY_LEN a->length += inc; #endif diff --git a/src/builtins.c b/src/builtins.c index 8495f0261a746..f1a3d6dd538e5 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -103,12 +103,6 @@ void NORETURN jl_type_error_rt(const char *fname, const char *context, jl_throw(ex); } -void NORETURN jl_type_error_rt_line(const char *fname, const char *context, - jl_value_t *ty, jl_value_t *got, int line) -{ - jl_type_error_rt(fname, context, ty, got); -} - void NORETURN jl_type_error(const char *fname, jl_value_t *expected, jl_value_t *got) { jl_type_error_rt(fname, "", expected, got); diff --git a/src/ccall.cpp b/src/ccall.cpp index c3a3ba4d4ae14..0df0428b40ee3 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -242,6 +242,8 @@ static Value *runtime_sym_lookup(PointerType *funcptype, char *f_lib, char *f_na # else # include "abi_x86.cpp" # endif +#elif defined _CPU_AARCH64_ +# include "abi_aarch64.cpp" #else # warning "ccall is defaulting to llvm ABI, since no platform ABI has been defined for this CPU/OS combination" # include "abi_llvm.cpp" diff --git a/src/ccalltest.c b/src/ccalltest.c index eec5dcd40624e..a4e47cb402268 100644 --- a/src/ccalltest.c +++ b/src/ccalltest.c @@ -5,17 +5,21 @@ #include #include #include -int verbose = 1; #include "../src/support/platform.h" #include "../src/support/dtypes.h" #ifdef _P64 #define jint int64_t +#define PRIjint PRId64 #else #define jint int32_t +#define PRIjint PRId32 #endif +int verbose = 1; + + ////////////////////////////////// // Test for proper argument register truncation @@ -31,11 +35,6 @@ DLLEXPORT testUcharX(unsigned char x) { return xs[x]; } -#define xstr(s) str(s) -#define str(s) #s -int (*volatile fptr)(unsigned char x); -volatile int a; -volatile int b; ////////////////////////////////// // Tests for passing and returning Structs @@ -82,7 +81,7 @@ DLLEXPORT complex float* cfptest(complex float *a) { DLLEXPORT complex_t* cptest(complex_t *a) { //Unpack a ComplexPair{Int} struct pointer - if (verbose) fprintf(stderr,"%lld + %lld i\n", (long long)a->real, (long long)a->imag); + if (verbose) fprintf(stderr,"%" PRIjint " + %" PRIjint " i\n", a->real, a->imag); a->real += 1; a->imag -= 2; return a; @@ -95,19 +94,6 @@ DLLEXPORT complex_t* cptest_static(complex_t *a) { return b; } -// Native-like data types -DLLEXPORT char* stest(char *x) { - //Print a character Array - if (verbose) fprintf(stderr,"%s\n", x); - return x; -} - -struct jl_asciistring_t { struct { void* type; char* data; } *data; }; -char* sptest(struct jl_asciistring_t str) { - //Unpack an ASCIIString - return stest(str.data->data); -} - // Various sized data types typedef struct { float x; @@ -198,163 +184,188 @@ typedef struct { double y; } struct15; +typedef struct { + float x,y,z; + double a,b,c; +} struct16; + typedef struct { jint x; jint y; char z; } struct_big; -DLLEXPORT struct1 test_1(struct1 a) { +DLLEXPORT struct1 test_1(struct1 a, float b) { //Unpack a "small" struct { float, double } - if (verbose) fprintf(stderr,"%g + %g i\n", a.x, a.y); - a.x += 1; - a.y -= 2; + if (verbose) fprintf(stderr,"%g + %g i & %g\n", a.x, a.y, b); + a.x += b * 1; + a.y -= b * 2; return a; } -DLLEXPORT struct1 add_1(struct1 a, struct1 b) { - // Two small structs - struct1 c; - c.x = a.x + b.x; - c.y = a.y + b.y; - return c; -} - -DLLEXPORT struct2a test_2a(struct2a a) { +DLLEXPORT struct2a test_2a(struct2a a, int32_t b) { //Unpack a ComplexPair{Int32} struct - if (verbose) fprintf(stderr,"%" PRId32 " + %" PRId32 " i\n", a.x.x, a.y.y); - a.x.x += 1; - a.y.y -= 2; + if (verbose) fprintf(stderr,"%" PRId32 " + %" PRId32 " i & %" PRId32 "\n", a.x.x, a.y.y, b); + a.x.x += b*1; + a.y.y -= b*2; return a; } -DLLEXPORT struct2b test_2b(struct2b a) { +DLLEXPORT struct2b test_2b(struct2b a, int32_t b) { //Unpack a ComplexPair{Int32} struct - if (verbose) fprintf(stderr,"%" PRId32 " + %" PRId32 " i\n", a.x, a.y); - a.x += 1; - a.y -= 2; + if (verbose) fprintf(stderr,"%" PRId32 " + %" PRId32 " i & %" PRId32 "\n", a.x, a.y, b); + a.x += b*1; + a.y -= b*2; return a; } -DLLEXPORT struct3a test_3a(struct3a a) { +DLLEXPORT struct3a test_3a(struct3a a, int64_t b) { //Unpack a ComplexPair{Int64} struct - if (verbose) fprintf(stderr,"%" PRId64 " + %" PRId64 " i\n", a.x.x, a.y.y); - a.x.x += 1; - a.y.y -= 2; + if (verbose) fprintf(stderr,"%" PRId64 " + %" PRId64 " i & %" PRId64 "\n", a.x.x, a.y.y, b); + a.x.x += b*1; + a.y.y -= b*2; return a; } -DLLEXPORT struct3b test_3b(struct3b a) { +DLLEXPORT struct3b test_3b(struct3b a, int64_t b) { //Unpack a ComplexPair{Int64} struct - if (verbose) fprintf(stderr,"%" PRId64 " + %" PRId64 " i\n", a.x, a.y); - a.x += 1; - a.y -= 2; + if (verbose) fprintf(stderr,"%" PRId64 " + %" PRId64 " i & %" PRId64 "\n", a.x, a.y, b); + a.x += b*1; + a.y -= b*2; return a; } -DLLEXPORT struct4 test_4(struct4 a) -{ - if (verbose) fprintf(stderr,"(%" PRId32 ",%" PRId32 ",%" PRId32 ")\n", a.x, a.y, a.z); - a.x += 1; - a.y -= 2; - a.z += 3; +DLLEXPORT struct4 test_4(struct4 a, int32_t b) { + if (verbose) fprintf(stderr,"%" PRId32 ",%" PRId32 ",%" PRId32 " & %" PRId32 "\n", a.x, a.y, a.z, b); + a.x += b*1; + a.y -= b*2; + a.z += b*3; return a; } +DLLEXPORT struct5 test_5(struct5 a, int32_t b) { + if (verbose) fprintf(stderr,"%" PRId32 ",%" PRId32 ",%" PRId32 ",%" PRId32 " & %" PRId32 "\n", a.x, a.y, a.z, a.a, b); + a.x += b*1; + a.y -= b*2; + a.z += b*3; + a.a -= b*4; -DLLEXPORT struct5 test_5(struct5 a) -{ - if (verbose) fprintf(stderr,"(%" PRId32 ",%" PRId32 ",%" PRId32 ",%" PRId32 ")\n", a.x, a.y, a.z, a.a); - a.x += 1; - a.y -= 2; - a.z += 3; - a.a -= 4; + return a; +} +DLLEXPORT struct6 test_6(struct6 a, int64_t b) { + if (verbose) fprintf(stderr,"%" PRId64 ",%" PRId64 ",%" PRId64 " & %" PRId64 "\n", a.x, a.y, a.z, b); + a.x += b*1; + a.y -= b*2; + a.z += b*3; return a; } +DLLEXPORT struct7 test_7(struct7 a, int8_t b) { + if (verbose) fprintf(stderr,"%" PRId64 ",%" PRId8 " & %" PRId8 "\n", a.x, a.y, b); + a.x += b*1; + a.y -= b*2; + return a; +} -DLLEXPORT struct6 test_6(struct6 a) -{ - if (verbose) fprintf(stderr,"(%" PRId64 ",%" PRId64 ",%" PRId64 ")\n", a.x, a.y, a.z); - a.x += 1; - a.y -= 2; - a.z += 3; +DLLEXPORT struct8 test_8(struct8 a, int8_t b) { + if (verbose) fprintf(stderr,"%" PRId32 ",%" PRId8 " & %" PRId8 "\n", a.x, a.y, b); + a.x += b*1; + a.y -= b*2; return a; } -DLLEXPORT struct7 test_7(struct7 a) -{ - if (verbose) fprintf(stderr,"(%" PRId64 ",%" PRId8 ")\n", a.x, a.y); - a.x += 1; - a.y -= 2; +DLLEXPORT struct9 test_9(struct9 a, int16_t b) { + if (verbose) fprintf(stderr,"%" PRId32 ",%" PRId16 " & %" PRId16 "\n", a.x, a.y, b); + a.x += b*1; + a.y -= b*2; return a; } -DLLEXPORT struct8 test_8(struct8 a) -{ - if (verbose) fprintf(stderr,"(%" PRId32 ",%" PRId8 ")\n", a.x, a.y); - a.x += 1; - a.y -= 2; +DLLEXPORT struct10 test_10(struct10 a, int8_t b) { + if (verbose) fprintf(stderr,"%" PRId8 ",%" PRId8 ",%" PRId8 ",%" PRId8 " & %" PRId8 "\n", a.x, a.y, a.z, a.a, b); + a.x += b*1; + a.y -= b*2; + a.z += b*3; + a.a -= b*4; + return a; } -DLLEXPORT struct9 test_9(struct9 a) -{ - if (verbose) fprintf(stderr,"(%" PRId32 ",%" PRId16 ")\n", a.x, a.y); - a.x += 1; - a.y -= 2; +DLLEXPORT struct11 test_11(struct11 a, float b) { + //Unpack a nested ComplexPair{Float32} struct + if (verbose) fprintf(stderr,"%g + %g i & %g\n", creal(a.x), cimag(a.x), b); + a.x += b*1 - (b*2.0*I); return a; } -DLLEXPORT struct10 test_10(struct10 a) -{ - if (verbose) fprintf(stderr,"(%" PRId8 ",%" PRId8 ",%" PRId8 ",%" PRId8 ")\n", a.x, a.y, a.z, a.a); - a.x += 1; - a.y -= 2; - a.z += 3; - a.a -= 4; +DLLEXPORT struct12 test_12(struct12 a, float b) { + //Unpack two nested ComplexPair{Float32} structs + if (verbose) fprintf(stderr,"%g + %g i & %g + %g i & %g\n", + creal(a.x), cimag(a.x), creal(a.y), cimag(a.y), b); + a.x += b*1 - (b*2.0*I); + a.y += b*3 - (b*4.0*I); + return a; +} +DLLEXPORT struct13 test_13(struct13 a, double b) { + //Unpack a nested ComplexPair{Float64} struct + if (verbose) fprintf(stderr,"%g + %g i & %g\n", creal(a.x), cimag(a.x), b); + a.x += b*1 - (b*2.0*I); return a; } -DLLEXPORT struct14 test_14(struct14 a) { +DLLEXPORT struct14 test_14(struct14 a, float b) { //The C equivalent of a ComplexPair{Float32} struct (but without special complex ABI) - if (verbose) fprintf(stderr,"%g + %g i\n", a.x, a.y); - a.x += 1; - a.y -= 2; + if (verbose) fprintf(stderr,"%g + %g i & %g\n", a.x, a.y, b); + a.x += b*1; + a.y -= b*2; return a; } -DLLEXPORT struct15 test_15(struct15 a) { - //The C equivalent of a ComplexPair{Float32} struct (but without special complex ABI) - if (verbose) fprintf(stderr,"%g + %g i\n", a.x, a.y); - a.x += 1; - a.y -= 2; +DLLEXPORT struct15 test_15(struct15 a, double b) { + //The C equivalent of a ComplexPair{Float64} struct (but without special complex ABI) + if (verbose) fprintf(stderr,"%g + %g i & %g\n", a.x, a.y, b); + a.x += b*1; + a.y -= b*2; + return a; +} + +DLLEXPORT struct16 test_16(struct16 a, float b) { + //Unpack a struct with non-obvious packing requirements + if (verbose) fprintf(stderr,"%g %g %g %g %g %g & %g\n", a.x, a.y, a.z, a.a, a.b, a.c, b); + a.x += b*1; + a.y -= b*2; + a.z += b*3; + a.a -= b*4; + a.b += b*5; + a.c -= b*6; return a; } #define int128_t struct3b -DLLEXPORT int128_t test_128(int128_t a) { +DLLEXPORT int128_t test_128(int128_t a, int64_t b) { //Unpack a Int128 - if (verbose) fprintf(stderr,"0x%016" PRIx64 "%016" PRIx64 "\n", a.y, a.x); - a.x += 1; + if (verbose) fprintf(stderr,"0x%016" PRIx64 "%016" PRIx64 " & %" PRId64 "\n", a.y, a.x, b); + a.x += b*1; if (a.x == 0) - a.y += 1; + a.y += b*1; return a; } DLLEXPORT struct_big test_big(struct_big a) { //Unpack a "big" struct { int, int, char } - if (verbose) fprintf(stderr,"%lld %lld %c\n", (long long)a.x, (long long)a.y, a.z); + if (verbose) fprintf(stderr,"%" PRIjint " %" PRIjint " %c\n", a.x, a.y, a.z); a.x += 1; a.y -= 2; a.z -= 'A'; return a; } + ////////////////////////////////// // Turn off verbose for automated tests, leave on for debugging + DLLEXPORT void set_verbose(int level) { verbose = level; } diff --git a/src/cgutils.cpp b/src/cgutils.cpp index e9225a1527245..db0cb7daf2b7a 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -688,15 +688,15 @@ DLLEXPORT Type *julia_type_to_llvm(jl_value_t *jt) if (jl_is_floattype(jt)) { #ifndef DISABLE_FLOAT16 if (nb == 2) - return Type::getHalfTy(jl_LLVMContext); + return T_float16; else #endif if (nb == 4) - return Type::getFloatTy(jl_LLVMContext); + return T_float32; else if (nb == 8) - return Type::getDoubleTy(jl_LLVMContext); + return T_float64; else if (nb == 16) - return Type::getFP128Ty(jl_LLVMContext); + return T_float128; } return Type::getIntNTy(jl_LLVMContext, nb*8); } @@ -1059,11 +1059,9 @@ static void raise_exception_unless(Value *cond, Value *exc, jl_codectx_t *ctx) builder.CreateCondBr(cond, passBB, failBB); builder.SetInsertPoint(failBB); #ifdef LLVM37 - builder.CreateCall(prepare_call(jlthrow_line_func), { exc, - ConstantInt::get(T_int32, ctx->lineno) }); + builder.CreateCall(prepare_call(jlthrow_func), { exc }); #else - builder.CreateCall2(prepare_call(jlthrow_line_func), exc, - ConstantInt::get(T_int32, ctx->lineno)); + builder.CreateCall(prepare_call(jlthrow_func), exc); #endif builder.CreateUnreachable(); ctx->f->getBasicBlockList().push_back(passBB); @@ -1107,13 +1105,11 @@ static void emit_type_error(Value *x, jl_value_t *type, const std::string &msg, #ifdef LLVM37 builder.CreateCall(prepare_call(jltypeerror_func), { fname_val, msg_val, - literal_pointer_val(type), boxed(x,ctx), - ConstantInt::get(T_int32, ctx->lineno) }); + literal_pointer_val(type), boxed(x,ctx)}); #else - builder.CreateCall5(prepare_call(jltypeerror_func), + builder.CreateCall4(prepare_call(jltypeerror_func), fname_val, msg_val, - literal_pointer_val(type), boxed(x,ctx), - ConstantInt::get(T_int32, ctx->lineno)); + literal_pointer_val(type), boxed(x,ctx)); #endif } diff --git a/src/codegen.cpp b/src/codegen.cpp index 1814d3bf72013..562974a42bf38 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -213,8 +213,10 @@ static IntegerType *T_uint64; static IntegerType *T_char; static IntegerType *T_size; +static Type *T_float16; static Type *T_float32; static Type *T_float64; +static Type *T_float128; static Type *T_pint8; static Type *T_pint16; @@ -298,7 +300,6 @@ extern RTDyldMemoryManager* createRTDyldMemoryManagerOSX(); // important functions static Function *jlnew_func; static Function *jlthrow_func; -static Function *jlthrow_line_func; static Function *jlerror_func; static Function *jltypeerror_func; static Function *jlundefvarerror_func; @@ -468,7 +469,6 @@ typedef struct { bool vaStack; // varargs stack-allocated bool sret; int nReqArgs; - int lineno; std::vector boundsCheck; jl_gcinfo_t gc; @@ -1272,7 +1272,7 @@ extern "C" void jl_write_malloc_log(void) static void show_source_loc(JL_STREAM *out, jl_codectx_t *ctx) { if (ctx == NULL) return; - jl_printf(out, "in %s at %s:%d", ctx->linfo->name->name, ctx->linfo->file->name, ctx->lineno); + jl_printf(out, "in %s at %s", ctx->linfo->name->name, ctx->linfo->file->name); } extern "C" void jl_binding_deprecation_warning(jl_binding_t *b); @@ -4187,7 +4187,6 @@ static Function *emit_function(jl_lambda_info_t *lam) } } } - ctx.lineno = lno; int toplineno = lno; DIBuilder dbuilder(*m); @@ -4199,6 +4198,7 @@ static Function *emit_function(jl_lambda_info_t *lam) DIFile topfile; DISubprogram SP; #endif + DebugLoc inlineLoc; BasicBlock *b0 = BasicBlock::Create(jl_LLVMContext, "top", f); builder.SetInsertPoint(b0); @@ -4279,7 +4279,8 @@ static Function *emit_function(jl_lambda_info_t *lam) f); // Function #endif // set initial line number - builder.SetCurrentDebugLocation(DebugLoc::get(lno, 0, (MDNode*)SP, NULL)); + inlineLoc = DebugLoc::get(lno, 0, (MDNode*)SP, NULL); + builder.SetCurrentDebugLocation(inlineLoc); #ifdef LLVM38 f->setSubprogram(SP); #endif @@ -4299,7 +4300,7 @@ static Function *emit_function(jl_lambda_info_t *lam) argname->name, // Variable name ctx.sret + i + 1, // Argument number (1-based) topfile, // File - ctx.lineno == -1 ? 0 : ctx.lineno, // Line + toplineno == -1 ? 0 : toplineno, // Line // Variable type julia_type_to_di(varinfo.declType,ctx.dbuilder,specsig)); #else @@ -4308,7 +4309,7 @@ static Function *emit_function(jl_lambda_info_t *lam) SP, // Scope (current function will be fill in later) argname->name, // Variable name topfile, // File - ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) + toplineno == -1 ? 0 : toplineno, // Line (for now, use lineno of the function) julia_type_to_di(varinfo.declType,ctx.dbuilder,specsig), // Variable type false, // May be optimized out 0, // Flags (TODO: Do we need any) @@ -4322,7 +4323,7 @@ static Function *emit_function(jl_lambda_info_t *lam) ctx.vaName->name, // Variable name ctx.sret + nreq + 1, // Argument number (1-based) topfile, // File - ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) + toplineno == -1 ? 0 : toplineno, // Line (for now, use lineno of the function) julia_type_to_di(ctx.vars[ctx.vaName].declType,ctx.dbuilder,false)); #else ctx.vars[ctx.vaName].dinfo = ctx.dbuilder->createLocalVariable( @@ -4330,7 +4331,7 @@ static Function *emit_function(jl_lambda_info_t *lam) SP, // Scope (current function will be fill in later) ctx.vaName->name, // Variable name topfile, // File - ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) + toplineno == -1 ? 0 : toplineno, // Line (for now, use lineno of the function) julia_type_to_di(ctx.vars[ctx.vaName].declType,ctx.dbuilder,false), // Variable type false, // May be optimized out 0, // Flags (TODO: Do we need any) @@ -4351,7 +4352,7 @@ static Function *emit_function(jl_lambda_info_t *lam) SP, // Scope (current function will be fill in later) s->name, // Variable name topfile, // File - ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) + toplineno == -1 ? 0 : toplineno, // Line (for now, use lineno of the function) julia_type_to_di(varinfo.declType,ctx.dbuilder,specsig), // Variable type false, // May be optimized out 0 // Flags (TODO: Do we need any) @@ -4375,7 +4376,7 @@ static Function *emit_function(jl_lambda_info_t *lam) SP, // Scope (current function will be filled in later) vname->name, // Variable name topfile, // File - ctx.lineno == -1 ? 0 : ctx.lineno, // Line (for now, use lineno of the function) + toplineno == -1 ? 0 : toplineno, // Line (for now, use lineno of the function) julia_type_to_di(varinfo.declType,ctx.dbuilder,specsig), // Variable type false, // May be optimized out 0 // Flags (TODO: Do we need any) @@ -4741,7 +4742,6 @@ static Function *emit_function(jl_lambda_info_t *lam) } DebugLoc loc; if (ctx.debug_enabled) { - MDNode *funcscope = (MDNode*)dbuilder.createLexicalBlockFile(SP, topfile); MDNode *scope; if ((dfil == topfile || dfil == NULL) && lno >= toplineno) @@ -4749,19 +4749,17 @@ static Function *emit_function(jl_lambda_info_t *lam) // for sequentially-defined code, // set location to line in top file. // TODO: improve handling of nested inlines - loc = DebugLoc::get(lno, 1, SP, NULL); + loc = inlineLoc = DebugLoc::get(lno, 1, SP, NULL); } else { // otherwise, we are compiling inlined code, // so set the DebugLoc "inlinedAt" parameter // to the current line, then use source loc. #ifdef LLVM37 scope = (MDNode*)dbuilder.createLexicalBlockFile(SP,dfil); - MDNode *inlineLocMd = DebugLoc::get(toplineno, 1, funcscope, NULL). - getAsMDNode(); + MDNode *inlineLocMd = inlineLoc.getAsMDNode(); #else scope = (MDNode*)dbuilder.createLexicalBlockFile(SP,DIFile(dfil)); - MDNode *inlineLocMd = DebugLoc::get(toplineno, 1, funcscope, NULL). - getAsMDNode(jl_LLVMContext); + MDNode *inlineLocMd = inlineLoc.getAsMDNode(jl_LLVMContext); #endif loc = DebugLoc::get(lno, 1, scope, inlineLocMd); } @@ -4769,7 +4767,6 @@ static Function *emit_function(jl_lambda_info_t *lam) } if (do_coverage) coverageVisitLine(filename, lno); - ctx.lineno = lno; // NOO TOUCHIE; NO TOUCH! See #922 } if (jl_is_labelnode(stmt)) { if (prevlabel) continue; @@ -4981,10 +4978,12 @@ static void init_julia_llvm_env(Module *m) else T_size = T_uint32; T_psize = PointerType::get(T_size, 0); + T_float16 = Type::getHalfTy(getGlobalContext()); T_float32 = Type::getFloatTy(getGlobalContext()); T_pfloat32 = PointerType::get(T_float32, 0); T_float64 = Type::getDoubleTy(getGlobalContext()); T_pfloat64 = PointerType::get(T_float64, 0); + T_float128 = Type::getFP128Ty(getGlobalContext()); T_void = Type::getVoidTy(jl_LLVMContext); // This type is used to create undef Values which carry metadata. @@ -5208,15 +5207,6 @@ static void init_julia_llvm_env(Module *m) jluboundserror_func->setDoesNotReturn(); add_named_global(jluboundserror_func, (void*)&jl_bounds_error_unboxed_int); - std::vector args2_throw(0); - args2_throw.push_back(jl_pvalue_llvmt); - args2_throw.push_back(T_int32); - jlthrow_line_func = - (Function*)m->getOrInsertFunction("jl_throw_with_superfluous_argument", - FunctionType::get(T_void, args2_throw, false)); - jlthrow_line_func->setDoesNotReturn(); - add_named_global(jlthrow_line_func, (void*)&jl_throw_with_superfluous_argument); - jlnew_func = Function::Create(jl_func_sig, Function::ExternalLinkage, "jl_new_structv", m); @@ -5247,13 +5237,12 @@ static void init_julia_llvm_env(Module *m) te_args.push_back(T_pint8); te_args.push_back(jl_pvalue_llvmt); te_args.push_back(jl_pvalue_llvmt); - te_args.push_back(T_int32); jltypeerror_func = Function::Create(FunctionType::get(T_void, te_args, false), Function::ExternalLinkage, - "jl_type_error_rt_line", m); + "jl_type_error_rt", m); jltypeerror_func->setDoesNotReturn(); - add_named_global(jltypeerror_func, (void*)&jl_type_error_rt_line); + add_named_global(jltypeerror_func, (void*)&jl_type_error_rt); std::vector args_2ptrs(0); args_2ptrs.push_back(jl_pvalue_llvmt); @@ -5695,13 +5684,16 @@ static inline SmallVector getTargetFeatures() { extern "C" void jl_init_codegen(void) { + const char *const argv_tailmerge[] = {"", "-enable-tail-merge=0"}; // NOO TOUCHIE; NO TOUCH! See #922 + cl::ParseCommandLineOptions(sizeof(argv_tailmerge)/sizeof(argv_tailmerge[0]), argv_tailmerge, "disable-tail-merge\n"); #if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_) - const char *const argv[] = {"", "-disable-copyprop"}; // llvm bug 21743 - cl::ParseCommandLineOptions(sizeof(argv)/sizeof(argv[0]), argv, "disable-copyprop\n"); + const char *const argv_copyprop[] = {"", "-disable-copyprop"}; // llvm bug 21743 + cl::ParseCommandLineOptions(sizeof(argv_copyprop)/sizeof(argv_copyprop[0]), argv_copyprop, "disable-copyprop\n"); #endif #ifdef JL_DEBUG_BUILD cl::ParseEnvironmentOptions("Julia", "JULIA_LLVM_ARGS"); #endif + #if defined(_CPU_PPC_) || defined(_CPU_PPC64_) imaging_mode = true; // LLVM seems to JIT bad TOC tables for the optimizations we attempt in non-imaging_mode #else diff --git a/src/dump.c b/src/dump.c index fe2788e993f0f..7529b7aaeedc7 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1493,6 +1493,7 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t jl_set_typeof(v, dt); if (dt == jl_datatype_type) return jl_deserialize_datatype(s, pos, loc); + assert(mode==MODE_AST || sz!=0 || loc); if ((mode == MODE_MODULE || mode == MODE_MODULE_POSTWORK) && dt == jl_typename_type) { int ref_only = read_uint8(s); if (ref_only) { @@ -1551,6 +1552,8 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t uptrint_t pos = backref_list.len; arraylist_push(&backref_list, (void*)v); if (mode == MODE_MODULE) { + // TODO: optimize the case where the value can easily be obtained + // from an external module (tag == 6) as dt->instance assert(loc != NULL); arraylist_push(&flagref_list, loc); arraylist_push(&flagref_list, (void*)pos); @@ -1629,7 +1632,11 @@ int jl_deserialize_verify_mod_list(ios_t *s) jl_errorf("invalid module path (%s does not name a module)", name); } if (m->uuid != uuid) { - jl_printf(JL_STDERR, "WARNING: Module %s uuid did not match cache file\n", name); + jl_printf(JL_STDERR, + "WARNING: Module %s uuid did not match cache file\n" + " This is likely because module %s does not support" + " precompilation but is imported by a module that does.\n", + name, name); return 0; } } @@ -1687,10 +1694,11 @@ static void jl_reinit_item(ios_t *f, jl_value_t *v, int how) { switch (how) { case 1: { // rehash ObjectIdDict jl_array_t **a = (jl_array_t**)jl_data_ptr(v); + // Assume *a don't need a write barrier jl_idtable_rehash(a, jl_array_len(*a)); jl_gc_wb(v, *a); break; - } + } case 2: { // reinsert module v into parent (const) jl_module_t *mod = (jl_module_t*)v; jl_binding_t *b = jl_get_binding_wr(mod->parent, mod->name); @@ -1707,7 +1715,7 @@ static void jl_reinit_item(ios_t *f, jl_value_t *v, int how) { b->value = v; jl_gc_wb_binding(b, v); break; - } + } default: assert(0); } @@ -2068,38 +2076,43 @@ DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) jl_function_t *jl_method_cache_insert(jl_methtable_t *mt, jl_tupletype_t *type, jl_function_t *method); -static jl_datatype_t *jl_recache_type(jl_datatype_t *dt, size_t start) +static jl_datatype_t *jl_recache_type(jl_datatype_t *dt, size_t start, jl_value_t *v) { - assert(dt->uid == -1); - jl_svec_t *tt = dt->parameters; - jl_value_t *v = dt->instance; // the instance before unique'ing + if (v == NULL) + v = dt->instance; // the instance before unique'ing jl_datatype_t *t; // the type after unique'ing - size_t l = jl_svec_len(tt); - if (l == 0) { // jl_cache_type doesn't work if length(parameters) == 0 - dt->uid = jl_assign_type_uid(); - t = dt; - } - else { - // recache all type parameters, then type type itself - size_t i; - for (i = 0; i < l; i++) { - jl_datatype_t *p = (jl_datatype_t*)jl_svecref(tt, i); - if (jl_is_datatype(p) && p->uid == -1) { - jl_datatype_t *cachep = jl_recache_type(p, start); - if (p != cachep) - jl_svecset(tt, i, cachep); - } - jl_datatype_t *tp = (jl_datatype_t*)jl_typeof(p); - if (jl_is_datatype_singleton(tp)) { - if (tp->uid == -1) { - tp = jl_recache_type(tp, start); + if (dt->uid == -1) { + jl_svec_t *tt = dt->parameters; + size_t l = jl_svec_len(tt); + if (l == 0) { // jl_cache_type doesn't work if length(parameters) == 0 + dt->uid = jl_assign_type_uid(); + t = dt; + } + else { + // recache all type parameters, then type type itself + size_t i; + for (i = 0; i < l; i++) { + jl_datatype_t *p = (jl_datatype_t*)jl_svecref(tt, i); + if (jl_is_datatype(p) && p->uid == -1) { + jl_datatype_t *cachep = jl_recache_type(p, start, NULL); + if (p != cachep) + jl_svecset(tt, i, cachep); + } + jl_datatype_t *tp = (jl_datatype_t*)jl_typeof(p); + if (jl_is_datatype_singleton(tp)) { + if (tp->uid == -1) { + tp = jl_recache_type(tp, start, NULL); + } + if ((jl_value_t*)p != tp->instance) + jl_svecset(tt, i, tp->instance); } - if ((jl_value_t*)p != tp->instance) - jl_svecset(tt, i, tp->instance); } + dt->uid = 0; + t = (jl_datatype_t*)jl_cache_type_(dt); } - dt->uid = 0; - t = (jl_datatype_t*)jl_cache_type_(dt); + } + else { + t = dt; } assert(t->uid != 0); // delete / replace any other usages of this type in the backref list @@ -2146,15 +2159,13 @@ static void jl_recache_types() if (jl_is_datatype(o)) { dt = (jl_datatype_t*)o; v = dt->instance; - t = jl_recache_type(dt, i); + assert(dt->uid == -1); + t = jl_recache_type(dt, i, NULL); } else { dt = (jl_datatype_t*)jl_typeof(o); v = o; - if (dt->uid == -1) - t = jl_recache_type(dt, i); - else - t = dt; + t = jl_recache_type(dt, i, v); } assert(dt); if (t != dt) { diff --git a/src/init.c b/src/init.c index 5debfbbe0176b..d4a990004ab7e 100644 --- a/src/init.c +++ b/src/init.c @@ -695,6 +695,7 @@ void jl_get_builtin_hooks(void) jl_uint32_type = (jl_datatype_t*)core("UInt32"); jl_uint64_type = (jl_datatype_t*)core("UInt64"); + jl_float16_type = (jl_datatype_t*)core("Float16"); jl_float32_type = (jl_datatype_t*)core("Float32"); jl_float64_type = (jl_datatype_t*)core("Float64"); jl_floatingpoint_type = (jl_datatype_t*)core("AbstractFloat"); diff --git a/src/interpreter.c b/src/interpreter.c index df6da9788cefe..c14e35511ebcf 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -21,6 +21,7 @@ static jl_value_t *eval_body(jl_array_t *stmts, jl_value_t **locals, size_t nl, int start, int toplevel); jl_value_t *jl_eval_module_expr(jl_expr_t *ex); int jl_is_toplevel_only_expr(jl_value_t *e); +extern void *jl_symbol_name(jl_sym_t *s); jl_value_t *jl_interpret_toplevel_expr(jl_value_t *e) { @@ -105,6 +106,22 @@ static void check_can_assign_type(jl_binding_t *b) jl_errorf("invalid redefinition of constant %s", b->name->name); } +void jl_reinstantiate_inner_types(jl_datatype_t *t); + +void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) +{ + if (!jl_is_datatype(super) || !jl_is_abstracttype(super) || + tt->name == ((jl_datatype_t*)super)->name || + jl_subtype(super,(jl_value_t*)jl_vararg_type,0) || + jl_is_tuple_type(super) || + jl_subtype(super,(jl_value_t*)jl_type_type,0)) { + jl_errorf("invalid subtyping in definition of %s", + jl_symbol_name(tt->name->name)); + } + tt->super = (jl_datatype_t*)super; + jl_gc_wb(tt, tt->super); +} + static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ngensym) { if (jl_is_symbol(e)) { @@ -354,6 +371,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ng jl_gc_wb_binding(b, dt); super = eval(args[2], locals, nl, ngensym); jl_set_datatype_super(dt, super); + jl_reinstantiate_inner_types(dt); b->value = temp; if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); @@ -384,6 +402,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ng jl_gc_wb_binding(b, dt); super = eval(args[3], locals, nl, ngensym); jl_set_datatype_super(dt, super); + jl_reinstantiate_inner_types(dt); b->value = temp; if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); @@ -413,6 +432,8 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ng jl_gc_wb_binding(b,dt); JL_TRY { + super = eval(args[3], locals, nl, ngensym); + jl_set_datatype_super(dt, super); // operations that can fail inside_typedef = 1; dt->types = (jl_svec_t*)eval(args[4], locals, nl, ngensym); @@ -423,8 +444,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ng if (!jl_is_type(elt) && !jl_is_typevar(elt)) jl_type_error_rt(dt->name->name->name, "type definition", (jl_value_t*)jl_type_type, elt); } - super = eval(args[3], locals, nl, ngensym); - jl_set_datatype_super(dt, super); + jl_reinstantiate_inner_types(dt); } JL_CATCH { b->value = temp; diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 5b5282fd8aaaa..971d14854900c 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -67,15 +67,15 @@ static Type *FTnbits(size_t nb) { #ifndef DISABLE_FLOAT16 if (nb == 16) - return Type::getHalfTy(jl_LLVMContext); + return T_float16; else #endif if (nb == 32) - return Type::getFloatTy(jl_LLVMContext); + return T_float32; else if (nb == 64) - return Type::getDoubleTy(jl_LLVMContext); + return T_float64; else if (nb == 128) - return Type::getFP128Ty(jl_LLVMContext); + return T_float128; else jl_error("Unsupported Float Size"); } diff --git a/src/jltypes.c b/src/jltypes.c index ad3e5df6dac2b..b55cc6bafe5e4 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -50,6 +50,7 @@ jl_datatype_t *jl_int32_type; jl_datatype_t *jl_uint32_type; jl_datatype_t *jl_int64_type; jl_datatype_t *jl_uint64_type; +jl_datatype_t *jl_float16_type; jl_datatype_t *jl_float32_type; jl_datatype_t *jl_float64_type; jl_datatype_t *jl_floatingpoint_type; @@ -2345,6 +2346,9 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) top.tt = t; top.prev = NULL; size_t n = jl_svec_len(t->parameters); + if (n == 0) return; + t->name->cache = jl_emptysvec; + t->name->linearcache = jl_emptysvec; jl_value_t **env = (jl_value_t**)alloca(n*2*sizeof(void*)); for(int i=0; i < n; i++) { env[i*2] = jl_svecref(t->parameters,i); diff --git a/src/julia.h b/src/julia.h index 51f3570a2fd53..eb919373a92ac 100644 --- a/src/julia.h +++ b/src/julia.h @@ -21,6 +21,9 @@ extern "C" { # define jl_jmp_buf sigjmp_buf # if defined(_CPU_ARM_) # define MAX_ALIGN 8 +# elif defined(_CPU_AARCH64_) +// int128 is 16 bytes aligned on aarch64 +# define MAX_ALIGN 16 # else # define MAX_ALIGN sizeof(void*) # endif @@ -434,6 +437,7 @@ extern DLLEXPORT jl_datatype_t *jl_int32_type; extern DLLEXPORT jl_datatype_t *jl_uint32_type; extern DLLEXPORT jl_datatype_t *jl_int64_type; extern DLLEXPORT jl_datatype_t *jl_uint64_type; +extern DLLEXPORT jl_datatype_t *jl_float16_type; extern DLLEXPORT jl_datatype_t *jl_float32_type; extern DLLEXPORT jl_datatype_t *jl_float64_type; extern DLLEXPORT jl_datatype_t *jl_floatingpoint_type; @@ -1150,8 +1154,6 @@ DLLEXPORT void NORETURN jl_too_many_args(const char *fname, int max); DLLEXPORT void NORETURN jl_type_error(const char *fname, jl_value_t *expected, jl_value_t *got); DLLEXPORT void NORETURN jl_type_error_rt(const char *fname, const char *context, jl_value_t *ty, jl_value_t *got); -DLLEXPORT void NORETURN jl_type_error_rt_line(const char *fname, const char *context, - jl_value_t *ty, jl_value_t *got, int line); DLLEXPORT void NORETURN jl_undefined_var_error(jl_sym_t *var); DLLEXPORT void NORETURN jl_bounds_error(jl_value_t *v, jl_value_t *t); DLLEXPORT void NORETURN jl_bounds_error_v(jl_value_t *v, jl_value_t **idxs, size_t nidxs); @@ -1405,7 +1407,6 @@ extern DLLEXPORT JL_THREAD jl_value_t *jl_exception_in_transit; DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, size_t ssize); DLLEXPORT jl_value_t *jl_switchto(jl_task_t *t, jl_value_t *arg); DLLEXPORT void NORETURN jl_throw(jl_value_t *e); -DLLEXPORT void NORETURN jl_throw_with_superfluous_argument(jl_value_t *e, int); DLLEXPORT void NORETURN jl_rethrow(void); DLLEXPORT void NORETURN jl_rethrow_other(jl_value_t *e); diff --git a/src/julia_internal.h b/src/julia_internal.h index 230bcd9f6de5a..d788995373b07 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -108,9 +108,6 @@ int jl_types_equal_generic(jl_value_t *a, jl_value_t *b, int useenv); jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np); jl_datatype_t *jl_inst_concrete_tupletype(jl_svec_t *p); -void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super); -void jl_add_constructors(jl_datatype_t *t); - jl_value_t *jl_nth_slot_type(jl_tupletype_t *sig, size_t i); void jl_compute_field_offsets(jl_datatype_t *st); jl_array_t *jl_new_array_for_deserialization(jl_value_t *atype, uint32_t ndims, size_t *dims, @@ -139,6 +136,8 @@ extern JL_THREAD void *jl_stackbase; void jl_dump_bitcode(char *fname, const char *sysimg_data, size_t sysimg_len); void jl_dump_objfile(char *fname, int jit_model, const char *sysimg_data, size_t sysimg_len); int32_t jl_get_llvm_gv(jl_value_t *p); +// the first argument to jl_idtable_rehash is used to return a value +// make sure it is rooted if it is used after the function returns void jl_idtable_rehash(jl_array_t **pa, size_t newsz); #ifdef _OS_LINUX_ diff --git a/src/table.c b/src/table.c index eb15018c34f36..8567db1129f77 100644 --- a/src/table.c +++ b/src/table.c @@ -12,26 +12,34 @@ static void **jl_table_lookup_bp(jl_array_t **pa, void *key); void jl_idtable_rehash(jl_array_t **pa, size_t newsz) { + // Assume *pa don't need a write barrier + // pa doesn't have to be a GC slot but *pa needs to be rooted size_t sz = jl_array_len(*pa); size_t i; void **ol = (void**)(*pa)->data; - *pa = jl_alloc_cell_1d(newsz); - // we do not check the write barrier here - // because pa always points to a C stack location - // (see eqtable_put) - // it should be changed if this assumption no longer holds + jl_array_t *newa = jl_alloc_cell_1d(newsz); + // keep the original array in the original slot since we need `ol` + // to be valid in the loop below. + JL_GC_PUSH1(&newa); for(i=0; i < sz; i+=2) { if (ol[i+1] != NULL) { - (*jl_table_lookup_bp(pa, ol[i])) = ol[i+1]; - jl_gc_wb(*pa, ol[i+1]); + (*jl_table_lookup_bp(&newa, ol[i])) = ol[i+1]; + jl_gc_wb(newa, ol[i+1]); // it is however necessary here because allocation // can (and will) occur in a recursive call inside table_lookup_bp } } + *pa = newa; + // we do not check the write barrier here + // because pa always points to a C stack location + // (see jl_eqtable_put and jl_finalize_deserializer) + // it should be changed if this assumption no longer holds + JL_GC_POP(); } static void **jl_table_lookup_bp(jl_array_t **pa, void *key) { + // pa points to a **rooted** gc frame slot uint_t hv; jl_array_t *a = *pa; size_t orig, index, iter; @@ -116,9 +124,12 @@ static void **jl_table_peek_bp(jl_array_t *a, void *key) DLLEXPORT jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val) { + JL_GC_PUSH1(&h); + // &h may be assigned to in jl_idtable_rehash so it need to be rooted void **bp = jl_table_lookup_bp(&h, key); *bp = val; jl_gc_wb(h, val); + JL_GC_POP(); return h; } diff --git a/src/task.c b/src/task.c index 99e8ac9647191..f2cde6166ae61 100644 --- a/src/task.c +++ b/src/task.c @@ -836,11 +836,6 @@ DLLEXPORT void jl_rethrow_other(jl_value_t *e) throw_internal(e); } -DLLEXPORT void jl_throw_with_superfluous_argument(jl_value_t *e, int line) -{ - jl_throw(e); -} - DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, size_t ssize) { size_t pagesz = jl_page_size; diff --git a/src/toplevel.c b/src/toplevel.c index 1e5f34aef1214..7d62055ed5780 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -625,28 +625,6 @@ DLLEXPORT jl_value_t *jl_load_(jl_value_t *str) return jl_load(jl_string_data(str), jl_string_len(str)); } -// type definition ------------------------------------------------------------ - -void jl_reinstantiate_inner_types(jl_datatype_t *t); - -void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) -{ - if (!jl_is_datatype(super) || !jl_is_abstracttype(super) || - tt->name == ((jl_datatype_t*)super)->name || - jl_subtype(super,(jl_value_t*)jl_vararg_type,0) || - jl_is_tuple_type(super) || - jl_subtype(super,(jl_value_t*)jl_type_type,0)) { - jl_errorf("invalid subtyping in definition of %s",tt->name->name->name); - } - tt->super = (jl_datatype_t*)super; - jl_gc_wb(tt, tt->super); - if (jl_svec_len(tt->parameters) > 0) { - tt->name->cache = jl_emptysvec; - tt->name->linearcache = jl_emptysvec; - jl_reinstantiate_inner_types(tt); - } -} - // method definition ---------------------------------------------------------- extern int jl_boot_file_loaded; diff --git a/test/backtrace.jl b/test/backtrace.jl index d5b9f3ad97c5f..bb76923617ee5 100644 --- a/test/backtrace.jl +++ b/test/backtrace.jl @@ -99,5 +99,6 @@ let ind2 = find(:test_throw_commoning .== map(b->code_loc(b)[1], b2)) @test !isempty(ind1) @test !isempty(ind2) - @test code_loc(b1[ind1[1]])[3] != code_loc(b2[ind2[1]])[3] + @test (code_loc(b1[ind1[1]])[3]::Int == code_loc(b2[ind2[1]])[3]::Int) != # source line, for example: essentials.jl:58 + (code_loc(b1[ind1[1]])[5]::Int == code_loc(b2[ind2[1]])[5]::Int) # inlined line, for example: backtrace.jl:82 end diff --git a/test/blas.jl b/test/blas.jl index b20e166ed41c3..2bf10b1b3d874 100644 --- a/test/blas.jl +++ b/test/blas.jl @@ -84,8 +84,8 @@ for elty in [Float32, Float64, Complex64, Complex128] @test_approx_eq BLAS.axpy!(α,copy(x1),copy(x2)) x2 + α*x1 @test_throws DimensionMismatch BLAS.axpy!(α, copy(x1), rand(elty, n + 1)) @test_throws DimensionMismatch BLAS.axpy!(α, copy(x1), 1:div(n,2), copy(x2), 1:n) - @test_throws BoundsError BLAS.axpy!(α, copy(x1), 0:div(n,2), copy(x2), 1:(div(n, 2) + 1)) - @test_throws BoundsError BLAS.axpy!(α, copy(x1), 1:div(n,2), copy(x2), 0:(div(n, 2) - 1)) + @test_throws ArgumentError BLAS.axpy!(α, copy(x1), 0:div(n,2), copy(x2), 1:(div(n, 2) + 1)) + @test_throws ArgumentError BLAS.axpy!(α, copy(x1), 1:div(n,2), copy(x2), 0:(div(n, 2) - 1)) @test_approx_eq BLAS.axpy!(α,copy(x1),1:n,copy(x2),1:n) x2 + α*x1 else z1 = convert(Vector{elty}, complex(randn(n), randn(n))) @@ -94,8 +94,8 @@ for elty in [Float32, Float64, Complex64, Complex128] @test_approx_eq BLAS.axpy!(α, copy(z1), copy(z2)) z2 + α * z1 @test_throws DimensionMismatch BLAS.axpy!(α, copy(z1), rand(elty, n + 1)) @test_throws DimensionMismatch BLAS.axpy!(α, copy(z1), 1:div(n, 2), copy(z2), 1:(div(n, 2) + 1)) - @test_throws BoundsError BLAS.axpy!(α, copy(z1), 0:div(n,2), copy(z2), 1:(div(n, 2) + 1)) - @test_throws BoundsError BLAS.axpy!(α, copy(z1), 1:div(n,2), copy(z2), 0:(div(n, 2) - 1)) + @test_throws ArgumentError BLAS.axpy!(α, copy(z1), 0:div(n,2), copy(z2), 1:(div(n, 2) + 1)) + @test_throws ArgumentError BLAS.axpy!(α, copy(z1), 1:div(n,2), copy(z2), 0:(div(n, 2) - 1)) @test_approx_eq BLAS.axpy!(α,copy(z1),1:n,copy(z2),1:n) z2 + α*z1 end @@ -150,8 +150,8 @@ for elty in [Float32, Float64, Complex64, Complex128] BLAS.copy!(x2, 1:n, x1, 1:n) @test x2 == x1 @test_throws DimensionMismatch BLAS.copy!(x2, 1:n, x1, 1:(n - 1)) - @test_throws BoundsError BLAS.copy!(x1, 0:div(n, 2), x2, 1:(div(n, 2) + 1)) - @test_throws BoundsError BLAS.copy!(x1, 1:(div(n, 2) + 1), x2, 0:div(n, 2)) + @test_throws ArgumentError BLAS.copy!(x1, 0:div(n, 2), x2, 1:(div(n, 2) + 1)) + @test_throws ArgumentError BLAS.copy!(x1, 1:(div(n, 2) + 1), x2, 0:div(n, 2)) # symv and hemv diff --git a/test/ccall.jl b/test/ccall.jl index ca0c9dde08e88..897931a1fe066 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -1,15 +1,19 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license import Base.copy, Base.== -const verbose = false + const libccalltest = "libccalltest" + +const verbose = false ccall((:set_verbose, libccalltest), Void, (Int32,), verbose) + # Test for proper argument register truncation ccall_test_func(x) = ccall((:testUcharX, libccalltest), Int32, (UInt8,), x % UInt8) @test ccall_test_func(3) == 1 @test ccall_test_func(259) == 1 + # Test for proper round-trip of Ref{T} type ccall_echo_func{T,U}(x, ::Type{T}, ::Type{U}) = ccall((:test_echo_p, libccalltest), T, (U,), x) # Make sure object x is still valid (rooted as argument) @@ -40,101 +44,374 @@ end @test ccall_echo_load(Ref([144,172],2), Ptr{Int}, Ref{Int}) === 172 # @test ccall_echo_load(Ref([8],1,1), Ptr{Int}, Ref{Int}) === 8 -# Tests for passing and returning structs -ci = 20+51im -b = ccall((:ctest, libccalltest), Complex{Int}, (Complex{Int},), ci) -@test b == ci + 1 - 2im -ci_ary = [ci] # Make sure the array is alive during unsafe_load -b = unsafe_load(ccall((:cptest, libccalltest), Ptr{Complex{Int}}, - (Ptr{Complex{Int}},), ci_ary)) -@test b == ci + 1 - 2im -@test ci == 20+51im -b = ccall((:cptest_static, libccalltest), Ptr{Complex{Int}}, (Ptr{Complex{Int}},), &ci) -@test unsafe_load(b) == ci -Libc.free(convert(Ptr{Void},b)) +## Tests for passing and returning structs -cf64 = 2.84+5.2im -b = ccall((:cgtest, libccalltest), Complex128, (Complex128,), cf64) -@test b == cf64 + 1 - 2im -cf64_ary = [cf64] # Make sure the array is alive during unsafe_load -b = unsafe_load(ccall((:cgptest, libccalltest), Ptr{Complex128}, (Ptr{Complex128},), cf64_ary)) -@test b == cf64 + 1 - 2im -@test cf64 == 2.84+5.2im +let + a = 20 + 51im -cf32 = 3.34f0+53.2f0im -b = ccall((:cftest, libccalltest), Complex64, (Complex64,), cf32) -@test b == cf32 + 1 - 2im -cf32_ary = [cf32] # Make sure the array is alive during unsafe_load -b = unsafe_load(ccall((:cfptest, libccalltest), Ptr{Complex64}, (Ptr{Complex64},), cf32_ary)) -@test b == cf32 + 1 - 2im -@test cf32 == 3.34f0+53.2f0im + x = ccall((:ctest, libccalltest), Complex{Int}, (Complex{Int},), a) + + @test x == a + 1 - 2im + + ci_ary = [a] # Make sure the array is alive during unsafe_load + x = unsafe_load(ccall((:cptest, libccalltest), Ptr{Complex{Int}}, + (Ptr{Complex{Int}},), ci_ary)) + + @test x == a + 1 - 2im + @test a == 20 + 51im + + x = ccall((:cptest_static, libccalltest), Ptr{Complex{Int}}, (Ptr{Complex{Int}},), &a) + @test unsafe_load(x) == a + Libc.free(convert(Ptr{Void},x)) +end + +let + a = 2.84 + 5.2im + + x = ccall((:cgtest, libccalltest), Complex128, (Complex128,), a) + + @test x == a + 1 - 2im + + b = [a] # Make sure the array is alive during unsafe_load + x = unsafe_load(ccall((:cgptest, libccalltest), Ptr{Complex128}, (Ptr{Complex128},), b)) + + @test x == a + 1 - 2im + @test a == 2.84 + 5.2im +end + +let + a = 3.34f0 + 53.2f0im + + x = ccall((:cftest, libccalltest), Complex64, (Complex64,), a) + + @test x == a + 1 - 2im + + b = [a] # Make sure the array is alive during unsafe_load + x = unsafe_load(ccall((:cfptest, libccalltest), Ptr{Complex64}, (Ptr{Complex64},), b)) + + @test x == a + 1 - 2im + @test a == 3.34f0 + 53.2f0im +end + + +## Tests for native Julia data types +let + a = 2.84 + 5.2im -# Tests for native Julia data types -@test_throws MethodError ccall((:cptest, libccalltest), Ptr{Complex{Int}}, (Ptr{Complex{Int}},), cf32) -@test_throws ErrorException ccall((:cptest, libccalltest), Ptr{Complex{Int}}, (Complex{Int},), &cf32) #compile-time error + @test_throws MethodError ccall((:cptest, libccalltest), Ptr{Complex{Int}}, (Ptr{Complex{Int}},), a) + @test_throws ErrorException ccall((:cptest, libccalltest), Ptr{Complex{Int}}, (Complex{Int},), &a) #compile-time error +end + + +## Tests for various sized data types (ByVal) -# Tests for various sized data types (ByVal) type Struct1 x::Float32 y::Float64 end -==(a::Struct1,b::Struct1) = a.x == b.x && a.y == b.y copy(a::Struct1) = Struct1(a.x, a.y) -s1 = Struct1(352.39422f23, 19.287577) -a = copy(s1) -b = ccall((:test_1, libccalltest), Struct1, (Struct1,), a) -@test a.x == s1.x && a.y == s1.y -@test !(a === b) -@test b.x == s1.x + 1 && b.y == s1.y - 2 -function foos1(s::Struct1) - @test !(s === a) - @test s == a - s +let + a = Struct1(352.39422f23, 19.287577) + b = Float32(123.456) + + a2 = copy(a) + x = ccall((:test_1, libccalltest), Struct1, (Struct1, Float32), a2, b) + + @test a2.x == a.x && a2.y == a.y + @test !(a2 === x) + + @test_approx_eq x.x a.x + 1*b + @test_approx_eq x.y a.y - 2*b end -ci32 = Complex{Int32}(Int32(10),Int32(31)) -ba = ccall((:test_2a, libccalltest), Complex{Int32}, (Complex{Int32},), ci32) -bb = ccall((:test_2b, libccalltest), Complex{Int32}, (Complex{Int32},), ci32) -@test ba == bb == ci32 + 1 - 2im -@test ci32 == Complex{Int32}(Int32(10),Int32(31)) +let + a = Complex{Int32}(Int32(10),Int32(31)) + b = Int32(42) -ci64 = Complex{Int64}(Int64(20),Int64(51)) -ba = ccall((:test_3a, libccalltest), Complex{Int64}, (Complex{Int64},), ci64) -bb = ccall((:test_3b, libccalltest), Complex{Int64}, (Complex{Int64},), ci64) -bc = ccall((:test_128, libccalltest), Complex{Int64}, (Complex{Int64},), ci64) -@test ba == bb == ci64 + 1 - 2im -@test bc == ci64 + 1 -@test ci64 == Complex{Int64}(Int64(20),Int64(51)) - -i128 = Int128(0x7f00123456789abc)<<64 + typemax(UInt64) -b = ccall((:test_128, libccalltest), Int128, (Int128,), i128) -@test b == i128 + 1 -@test i128 == Int128(0x7f00123456789abc)<<64 + typemax(UInt64) + x = ccall((:test_2a, libccalltest), Complex{Int32}, (Complex{Int32}, Int32), a, b) + y = ccall((:test_2b, libccalltest), Complex{Int32}, (Complex{Int32},Int32), a, b) + + @test a == Complex{Int32}(Int32(10),Int32(31)) + + @test x == y + @test x == a + b*1 - b*2im +end + +let + a = Complex{Int64}(Int64(20),Int64(51)) + b = Int64(42) + + x = ccall((:test_3a, libccalltest), Complex{Int64}, (Complex{Int64}, Int64), a, b) + y = ccall((:test_3b, libccalltest), Complex{Int64}, (Complex{Int64}, Int64), a, b) + z = ccall((:test_128, libccalltest), Complex{Int64}, (Complex{Int64}, Int64), a, b) + + @test a == Complex{Int64}(Int64(20),Int64(51)) + + @test x == y + @test x == a + b*1 - b*2im + + @test z == a + 1*b +end + +type Struct4 + x::Int32 + y::Int32 + z::Int32 +end + +let + a = Struct4(-512275808,882558299,-2133022131) + b = Int32(42) + + x = ccall((:test_4, libccalltest), Struct4, (Struct4,Int32), a, b) + + @test x.x == a.x+b*1 + @test x.y == a.y-b*2 + @test x.z == a.z+b*3 +end + +type Struct5 + x::Int32 + y::Int32 + z::Int32 + a::Int32 +end + +let + a = Struct5(1771319039, 406394736, -1269509787, -745020976) + b = Int32(42) + + x = ccall((:test_5, libccalltest), Struct5, (Struct5,Int32), a, b) + + @test x.x == a.x+b*1 + @test x.y == a.y-b*2 + @test x.z == a.z+b*3 + @test x.a == a.a-b*4 +end + +type Struct6 + x::Int64 + y::Int64 + z::Int64 +end + +let + a = Struct6(-654017936452753226, -5573248801240918230, -983717165097205098) + b = Int64(42) + + x = ccall((:test_6, libccalltest), Struct6, (Struct6, Int64), a, b) + + @test x.x == a.x+b*1 + @test x.y == a.y-b*2 + @test x.z == a.z+b*3 +end + +type Struct7 + x::Int64 + y::Cchar +end + +let + a = Struct7(-384082741977533896, 'h') + b = Int8(42) + + x = ccall((:test_7, libccalltest), Struct7, (Struct7,Int8), a, b) + + @test x.x == a.x+Int(b)*1 + @test x.y == a.y-Int(b)*2 +end + +type Struct8 + x::Int32 + y::Cchar +end + +let + a = Struct8(-384082896, 'h') + b = Int8(42) + + r8 = ccall((:test_8, libccalltest), Struct8, (Struct8,Int8), a, b) + + @test r8.x == a.x+b*1 + @test r8.y == a.y-b*2 +end + +type Struct9 + x::Int32 + y::Int16 +end + +let + a = Struct9(-394092996, -3840) + b = Int16(42) + + x = ccall((:test_9, libccalltest), Struct9, (Struct9,Int16), a, b) + + @test x.x == a.x+b*1 + @test x.y == a.y-b*2 +end + +type Struct10 + x::Cchar + y::Cchar + z::Cchar + a::Cchar +end + +let + a = Struct10('0', '1', '2', '3') + b = Int8(2) + + x = ccall((:test_10, libccalltest), Struct10, (Struct10,Int8), a, b) + + @test x.x == a.x+b*1 + @test x.y == a.y-b*2 + @test x.z == a.z+b*3 + @test x.a == a.a-b*4 +end + +type Struct11 + x::Complex64 +end + +let + a = Struct11(0.8877077f0 + 0.4591081f0im) + b = Float32(42) + + x = ccall((:test_11, libccalltest), Struct11, (Struct11,Float32), a, b) + + @test_approx_eq x.x a.x + b*1 - b*2im +end + +type Struct12 + x::Complex64 + y::Complex64 +end + +let + a = Struct12(0.8877077f5 + 0.4591081f2im, 0.0004842868f0 - 6982.3265f3im) + b = Float32(42) + + x = ccall((:test_12, libccalltest), Struct12, (Struct12,Float32), a, b) + + @test_approx_eq x.x a.x + b*1 - b*2im + @test_approx_eq x.y a.y + b*3 - b*4im +end + +type Struct13 + x::Complex128 +end + +let + a = Struct13(42968.97560380495 - 803.0576845153616im) + b = Float64(42) + + x = ccall((:test_13, libccalltest), Struct13, (Struct13,Float64), a, b) + + @test_approx_eq x.x a.x + b*1 - b*2im +end + +type Struct14 + x::Float32 + y::Float32 +end + +let + a = Struct14(0.024138331f0, 0.89759064f32) + b = Float32(42) + + x = ccall((:test_14, libccalltest), Struct14, (Struct14,Float32), a, b) + + @test_approx_eq x.x a.x + b*1 + @test_approx_eq x.y a.y - b*2 +end + +type Struct15 + x::Float64 + y::Float64 +end + +let + a = Struct15(4.180997967273657, -0.404218594294923) + b = Float64(42) + + x = ccall((:test_15, libccalltest), Struct15, (Struct15,Float64), a, b) + + @test_approx_eq x.x a.x + b*1 + @test_approx_eq x.y a.y - b*2 +end + +type Struct16 + x::Float32 + y::Float32 + z::Float32 + a::Float64 + b::Float64 + c::Float64 +end + +let + a = Struct16(0.1604656f0, 0.6297606f0, 0.83588994f0, + 0.6460273620993535, 0.9472692581106656, 0.47328535437352093) + b = Float32(42) + + x = ccall((:test_16, libccalltest), Struct16, (Struct16,Float32), a, b) + + @test_approx_eq x.x a.x + b*1 + @test_approx_eq x.y a.y - b*2 + @test_approx_eq x.z a.z + b*3 + @test_approx_eq x.a a.a - b*4 + @test_approx_eq x.b a.b + b*5 + @test_approx_eq x.c a.c - b*6 +end + +let + a = Int128(0x7f00123456789abc)<<64 + typemax(UInt64) + b = Int64(1) + + x = ccall((:test_128, libccalltest), Int128, (Int128, Int64), a, b) + + @test x == a + b*1 + @test a == Int128(0x7f00123456789abc)<<64 + typemax(UInt64) +end type Struct_Big x::Int y::Int z::Int8 end -==(a::Struct_Big,b::Struct_Big) = a.x == b.x && a.y == b.y && a.z == b.z copy(a::Struct_Big) = Struct_Big(a.x, a.y, a.z) -sbig = Struct_Big(424,-5,Int8('Z')) -a = copy(sbig) -b = ccall((:test_big, libccalltest), Struct_Big, (Struct_Big,), a) -@test a.x == sbig.x && a.y == sbig.y && a.z == sbig.z -@test b.x == sbig.x + 1 -@test b.y == sbig.y - 2 -@test b.z == sbig.z - Int('A') +let + a = Struct_Big(424,-5,Int8('Z')) + a2 = copy(a) + + x = ccall((:test_big, libccalltest), Struct_Big, (Struct_Big,), a2) + + @test a2.x == a.x && a2.y == a.y && a2.z == a.z + @test x.x == a.x + 1 + @test x.y == a.y - 2 + @test x.z == a.z - Int('A') +end + + +## cfunction roundtrip verbose && Libc.flush_cstdio() verbose && println("Testing cfunction roundtrip: ") -# cfunction roundtrip + +cf64 = 2.84+5.2im +cf32 = 3.34f0+53.2f0im +ci32 = Complex{Int32}(Int32(10),Int32(31)) +ci64 = Complex{Int64}(Int64(20),Int64(51)) +s1 = Struct1(352.39422f23, 19.287577) +==(a::Struct1,b::Struct1) = a.x == b.x && a.y == b.y + for (t,v) in ((Complex{Int32},:ci32),(Complex{Int64},:ci64), - (Complex64,:cf32),(Complex128,:cf64),(Struct1,:s1)) + (Complex64,:cf32),(Complex128,:cf64),(Struct1,:s1)) fname = symbol("foo"*string(v)) fname1 = symbol("foo1"*string(v)) @eval begin diff --git a/test/core.jl b/test/core.jl index 41d25b3359f40..67e71205ae393 100644 --- a/test/core.jl +++ b/test/core.jl @@ -3454,3 +3454,76 @@ function __f_isa_arg_1() length(a) end @test __f_isa_arg_1() == 1 + +# issue #14825 +abstract abstest_14825 + +type t1_14825{A <: abstest_14825, B} + x::A + y::B +end + +type t2_14825{C, B} <: abstest_14825 + x::C + y::t1_14825{t2_14825{C, B}, B} +end + +@test t2_14825{Int,Int}.types[2] <: t1_14825 + +let ary = Vector{Any}(10) + check_undef_and_fill(ary, rng) = for i in rng + @test !isdefined(ary, i) + ary[i] = (Float64(i), i) # some non-cached content + @test isdefined(ary, i) + end + # Check if the memory is initially zerod and fill it with value + # to check if these values are not reused later. + check_undef_and_fill(ary, 1:10) + # Check if the memory grown at the end are zerod + ccall(:jl_array_grow_end, Void, (Any, Csize_t), ary, 10) + check_undef_and_fill(ary, 11:20) + # Make sure the content of the memory deleted at the end are not reused + ccall(:jl_array_del_end, Void, (Any, Csize_t), ary, 5) + ccall(:jl_array_grow_end, Void, (Any, Csize_t), ary, 5) + check_undef_and_fill(ary, 16:20) + + # Now check grow/del_end + ary = Vector{Any}(1010) + check_undef_and_fill(ary, 1:1010) + # This del_beg should move the buffer + ccall(:jl_array_del_beg, Void, (Any, Csize_t), ary, 1000) + ccall(:jl_array_grow_beg, Void, (Any, Csize_t), ary, 1000) + check_undef_and_fill(ary, 1:1000) + ary = Vector{Any}(1010) + check_undef_and_fill(ary, 1:1010) + # This del_beg should not move the buffer + ccall(:jl_array_del_beg, Void, (Any, Csize_t), ary, 10) + ccall(:jl_array_grow_beg, Void, (Any, Csize_t), ary, 10) + check_undef_and_fill(ary, 1:10) + + ary = Vector{Any}(1010) + check_undef_and_fill(ary, 1:1010) + ccall(:jl_array_grow_end, Void, (Any, Csize_t), ary, 10) + check_undef_and_fill(ary, 1011:1020) + ccall(:jl_array_del_end, Void, (Any, Csize_t), ary, 10) + ccall(:jl_array_grow_beg, Void, (Any, Csize_t), ary, 10) + check_undef_and_fill(ary, 1:10) + + # Make sure newly malloc'd buffers are filled with 0 + # test this for a few different sizes since we need to make sure + # we are malloc'ing the buffer after the grow_end and malloc is not using + # mmap directly (which may return a zero'd new page). + for n in [50, 51, 100, 101, 200, 201, 300, 301] + ary = Vector{Any}(n) + # Try to free the previous buffer that was filled with random content + # and to increase the chance of getting a non-zero'd buffer next time + gc() + gc() + gc() + ccall(:jl_array_grow_beg, Void, (Any, Csize_t), ary, 4) + ccall(:jl_array_del_beg, Void, (Any, Csize_t), ary, 4) + ccall(:jl_array_grow_end, Void, (Any, Csize_t), ary, n) + ccall(:jl_array_grow_beg, Void, (Any, Csize_t), ary, 4) + check_undef_and_fill(ary, 1:(2n + 4)) + end +end diff --git a/test/dict.jl b/test/dict.jl index 1de632b7a3c5d..07bcf50167150 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -356,3 +356,24 @@ d = Dict('a'=>1, 'b'=>1, 'c'=> 3) @test_throws ArgumentError Dict(0) @test_throws ArgumentError Dict([1]) @test_throws ArgumentError Dict([(1,2),0]) + +# issue #15077 +let badKeys = ASCIIString["FINO_emv5.0","FINO_ema0.1","RATE_ema1.0","NIBPM_ema1.0", + "SAO2_emv5.0","O2FLOW_ema5.0","preop_Neuro/Psych_","gender_", + "FIO2_ema0.1","PEAK_ema5.0","preop_Reproductive_denies","O2FLOW_ema0.1", + "preop_Endocrine_denies","preop_Respiratory_", + "NIBPM_ema0.1","PROPOFOL_MCG/KG/MIN_decay5.0","NIBPD_ema1.0","NIBPS_ema5.0", + "anesthesiaStartTime","NIBPS_ema1.0","RESPRATE_ema1.0","PEAK_ema0.1", + "preop_GU_denies","preop_Cardiovascular_","PIP_ema5.0","preop_ENT_denies", + "preop_Skin_denies","preop_Renal_denies","asaCode_IIIE","N2OFLOW_emv5.0", + "NIBPD_emv5.0", # <--- here is the key that we later can't find + "NIBPM_ema5.0","preop_Respiratory_complete","ETCO2_ema5.0", + "RESPRATE_ema0.1","preop_Functional Status_<2","preop_Renal_symptoms", + "ECGRATE_ema5.0","FIO2_emv5.0","RESPRATE_emv5.0","7wu3ty0a4fs","BVO", + "4UrCWXUsaT"] + d = Dict{AbstractString,Float64}() + for k in badKeys + d[k] = 1 + end + @test d["NIBPD_emv5.0"] == 1 +end diff --git a/test/iobuffer.jl b/test/iobuffer.jl index 991d244676e22..f18ebc5e647b4 100644 --- a/test/iobuffer.jl +++ b/test/iobuffer.jl @@ -192,16 +192,22 @@ let bstream = BufferStream() @test isopen(bstream) @test isreadable(bstream) @test iswritable(bstream) + @test nb_available(bstream) == 0 @test sprint(io -> show(io,bstream)) == "BufferStream() bytes waiting:$(nb_available(bstream.buffer)), isopen:true" a = rand(UInt8,10) write(bstream,a) + @test !eof(bstream) flush(bstream) b = read(bstream,UInt8) @test a[1] == b b = read(bstream,UInt8) @test a[2] == b c = zeros(UInt8,8) + @test nb_available(bstream) == 8 + @test !eof(bstream) read!(bstream,c) @test c == a[3:10] close(bstream) + @test eof(bstream) + @test nb_available(bstream) == 0 end diff --git a/test/linalg/generic.jl b/test/linalg/generic.jl index 1751f34e9be76..174496c2c8cfb 100644 --- a/test/linalg/generic.jl +++ b/test/linalg/generic.jl @@ -57,9 +57,8 @@ y = ['a','b','c','d','e'] @test_throws DimensionMismatch Base.LinAlg.axpy!(α,x,['g']) @test_throws BoundsError Base.LinAlg.axpy!(α,x,collect(-1:5),y,collect(1:7)) @test_throws BoundsError Base.LinAlg.axpy!(α,x,collect(1:7),y,collect(-1:5)) -@test_throws ArgumentError Base.LinAlg.axpy!(α,x,collect(1:3),y,collect(1:5)) @test_throws BoundsError Base.LinAlg.axpy!(α,x,collect(1:7),y,collect(1:7)) -@test_throws DimensionMismatch Base.LinAlg.axpy!(α,x,collect(1:2),['a','b'],collect(1:2)) +@test_throws DimensionMismatch Base.LinAlg.axpy!(α,x,collect(1:3),y,collect(1:5)) @test_throws ArgumentError diag(rand(10)) @test !issym(ones(5,3)) @@ -152,3 +151,13 @@ let @test LinAlg.axpy!(α, x, deepcopy(y)) == x .* Matrix{Int}[α] @test LinAlg.axpy!(α, x, deepcopy(y)) != Matrix{Int}[α] .* x end + +# test that LinAlg.axpy! works for x and y of different dimensions +let + α = 5 + x = 2:5 + y = ones(Int, 2, 4) + rx = [1 4] + ry = [2 8] + @test LinAlg.axpy!(α, x, rx, y, ry) == [1 1 1 1; 11 1 1 26] +end diff --git a/test/linalg/matmul.jl b/test/linalg/matmul.jl index ba8d2ae586fa0..8c57ca0edf3d2 100644 --- a/test/linalg/matmul.jl +++ b/test/linalg/matmul.jl @@ -32,6 +32,7 @@ Bi = B+(2.5*im).*A[[2,1],[2,1]] @test Ac_mul_B(Ai, Bi) == [68.5-12im 57.5-28im; 88-3im 76.5-25im] @test A_mul_Bc(Ai, Bi) == [64.5+5.5im 43+31.5im; 104-18.5im 80.5+31.5im] @test Ac_mul_Bc(Ai, Bi) == [-28.25-66im 9.75-58im; -26-89im 21-73im] +@test_throws DimensionMismatch [1 2; 0 0; 0 0] * [1 2] # 3x3 A = [1 2 3; 4 5 6; 7 8 9].-5 @@ -46,6 +47,7 @@ Bi = B+(2.5*im).*A[[2,1,3],[2,3,1]] @test Ac_mul_B(Ai, Bi) == [-21+2im -1.75+49im -51.25+19.5im; 25.5+56.5im -7-35.5im 22+35.5im; -3+12im -32.25+43im -34.75-2.5im] @test A_mul_Bc(Ai, Bi) == [-20.25+15.5im -28.75-54.5im 22.25+68.5im; -12.25+13im -15.5+75im -23+27im; 18.25+im 1.5+94.5im -27-54.5im] @test Ac_mul_Bc(Ai, Bi) == [1+2im 20.75+9im -44.75+42im; 19.5+17.5im -54-36.5im 51-14.5im; 13+7.5im 11.25+31.5im -43.25-14.5im] +@test_throws DimensionMismatch [1 2 3; 0 0 0; 0 0 0] * [1 2 3] # Generic integer matrix multiplication A = [1 2 3; 4 5 6] .- 3 @@ -109,6 +111,16 @@ Aref = Ai[1:2:end,1:2:end] Asub = sub(Ai, 1:2:5, 1:2:4) @test Ac_mul_B(Asub, Asub) == Ac_mul_B(Aref, Aref) @test A_mul_Bc(Asub, Asub) == A_mul_Bc(Aref, Aref) +# issue #15286 +let C = zeros(8, 8), sC = sub(C, 1:2:8, 1:2:8), B = reshape(map(Float64,-9:10),5,4) + @test At_mul_B!(sC, A, A) == A'*A + @test At_mul_B!(sC, A, B) == A'*B +end +let Aim = A .- im, C = zeros(Complex128,8,8), sC = sub(C, 1:2:8, 1:2:8), B = reshape(map(Float64,-9:10),5,4) .+ im + @test Ac_mul_B!(sC, Aim, Aim) == Aim'*Aim + @test Ac_mul_B!(sC, Aim, B) == Aim'*B +end + # syrk & herk A = reshape(1:1503, 501, 3).-750.0 diff --git a/test/linalg/tridiag.jl b/test/linalg/tridiag.jl index 972ed266a453d..fa89213723533 100644 --- a/test/linalg/tridiag.jl +++ b/test/linalg/tridiag.jl @@ -212,7 +212,7 @@ let n = 12 #Size of matrix problem to test @test diag(A,-1) == b @test diag(A,0) == a @test diag(A,n-1) == zeros(elty,1) - @test_throws BoundsError diag(A,n+1) + @test_throws ArgumentError diag(A,n+1) debug && println("Idempotent tests") for func in (conj, transpose, ctranspose) @@ -331,7 +331,7 @@ let n = 12 #Size of matrix problem to test @test diag(A,0) == b @test diag(A,1) == c @test diag(A,n-1) == zeros(elty,1) - @test_throws BoundsError diag(A,n+1) + @test_throws ArgumentError diag(A,n+1) debug && println("Simple unary functions") for func in (det, inv) diff --git a/test/markdown.jl b/test/markdown.jl index 75fb6abfe0f1f..2e015f6b722dc 100644 --- a/test/markdown.jl +++ b/test/markdown.jl @@ -41,6 +41,14 @@ foo @test md"``code```more code``" == MD(Any[Paragraph(Any[Code("","code```more code")])]) @test md"``code``````more code``" == MD(Any[Paragraph(Any[Code("","code``````more code")])]) +code_in_code = md""" +```` +``` +```` +""" +@test code_in_code == MD(Code("```")) +@test plain(code_in_code) == "````\n```\n````\n" + @test md""" * one * two diff --git a/test/numbers.jl b/test/numbers.jl index 3e334fb0e9b72..03b5e4bf2a124 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -2421,6 +2421,9 @@ end @test true*pi === Float64(pi) @test pi*true === Float64(pi) +# issue #5492 +@test -0.0 + false === -0.0 + # issue #5881 @test bits(true) == "00000001" @test bits(false) == "00000000" diff --git a/test/repl.jl b/test/repl.jl index ea4e03cc06804..cf46daea0e2ce 100644 --- a/test/repl.jl +++ b/test/repl.jl @@ -29,103 +29,103 @@ ccall(:jl_exit_on_sigint, Void, (Cint,), 0) # this should make sure nothing crashes without depending on how exactly the control # characters are being used. if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) -stdin_write, stdout_read, stderr_read, repl = fake_repl() + stdin_write, stdout_read, stderr_read, repl = fake_repl() -repl.specialdisplay = Base.REPL.REPLDisplay(repl) -repl.history_file = false - -repltask = @async begin - Base.REPL.run_repl(repl) -end - -sendrepl(cmd) = write(stdin_write,"inc || wait(b); r = $cmd; notify(c); r\r") - -inc = false -b = Condition() -c = Condition() -sendrepl("\"Hello REPL\"") -inc=true -begin - notify(b) - wait(c) -end -# Latex completions -write(stdin_write, "\x32\\alpha\t") -readuntil(stdout_read, "α") -# Bracketed paste in search mode -write(stdin_write, "\e[200~paste here ;)\e[201~") -# Abort search (^C) -write(stdin_write, '\x03') -# Test basic completion in main mode -write(stdin_write, "Base.REP\t") -readuntil(stdout_read, "Base.REPL") -write(stdin_write, '\x03') -write(stdin_write, "\\alpha\t") -readuntil(stdout_read,"α") -write(stdin_write, '\x03') -# Test cd feature in shell mode. We limit to 40 characters when -# calling readuntil() to suppress the warning it (currently) gives for -# long strings. -origpwd = pwd() -tmpdir = mktempdir() -write(stdin_write, ";") -readuntil(stdout_read, "shell> ") -write(stdin_write, "cd $(escape_string(tmpdir))\n") -readuntil(stdout_read, "cd $(escape_string(tmpdir))"[max(1,end-39):end]) -readuntil(stdout_read, realpath(tmpdir)[max(1,end-39):end]) -readuntil(stdout_read, "\n") -readuntil(stdout_read, "\n") -@test pwd() == realpath(tmpdir) -write(stdin_write, ";") -readuntil(stdout_read, "shell> ") -write(stdin_write, "cd -\n") -readuntil(stdout_read, origpwd[max(1,end-39):end]) -readuntil(stdout_read, "\n") -readuntil(stdout_read, "\n") -@test pwd() == origpwd -write(stdin_write, ";") -readuntil(stdout_read, "shell> ") -write(stdin_write, "cd\n") -readuntil(stdout_read, homedir()[max(1,end-39):end]) -readuntil(stdout_read, "\n") -readuntil(stdout_read, "\n") -@test pwd() == homedir() -rm(tmpdir) -cd(origpwd) - -# Test that accepting a REPL result immediately shows up, not -# just on the next keystroke -write(stdin_write, "1+1\n") # populate history with a trivial input -readline(stdout_read) -write(stdin_write, "\e[A\n") -t = Timer(10) do t - isopen(t) || return - error("Stuck waiting for the repl to write `1+1`") -end -# yield make sure this got processed -readuntil(stdout_read, "1+1") -close(t) - -# Issue #10222 -# Test ignoring insert key in standard and prefix search modes -write(stdin_write, "\e[2h\e[2h\n") # insert (VT100-style) -@test search(readline(stdout_read), "[2h") == 0:-1 -readline(stdout_read) -write(stdin_write, "\e[2~\e[2~\n") # insert (VT220-style) -@test search(readline(stdout_read), "[2~") == 0:-1 -readline(stdout_read) -write(stdin_write, "1+1\n") # populate history with a trivial input -readline(stdout_read) -write(stdin_write, "\e[A\e[2h\n") # up arrow, insert (VT100-style) -readline(stdout_read) -readline(stdout_read) -write(stdin_write, "\e[A\e[2~\n") # up arrow, insert (VT220-style) -readline(stdout_read) -readline(stdout_read) - -# Close REPL ^D -write(stdin_write, '\x04') -wait(repltask) + repl.specialdisplay = Base.REPL.REPLDisplay(repl) + repl.history_file = false + + repltask = @async begin + Base.REPL.run_repl(repl) + end + + sendrepl(cmd) = write(stdin_write,"inc || wait(b); r = $cmd; notify(c); r\r") + + inc = false + b = Condition() + c = Condition() + sendrepl("\"Hello REPL\"") + inc=true + begin + notify(b) + wait(c) + end + # Latex completions + write(stdin_write, "\x32\\alpha\t") + readuntil(stdout_read, "α") + # Bracketed paste in search mode + write(stdin_write, "\e[200~paste here ;)\e[201~") + # Abort search (^C) + write(stdin_write, '\x03') + # Test basic completion in main mode + write(stdin_write, "Base.REP\t") + readuntil(stdout_read, "Base.REPL") + write(stdin_write, '\x03') + write(stdin_write, "\\alpha\t") + readuntil(stdout_read,"α") + write(stdin_write, '\x03') + # Test cd feature in shell mode. We limit to 40 characters when + # calling readuntil() to suppress the warning it (currently) gives for + # long strings. + origpwd = pwd() + tmpdir = mktempdir() + write(stdin_write, ";") + readuntil(stdout_read, "shell> ") + write(stdin_write, "cd $(escape_string(tmpdir))\n") + readuntil(stdout_read, "cd $(escape_string(tmpdir))"[max(1,end-39):end]) + readuntil(stdout_read, realpath(tmpdir)[max(1,end-39):end]) + readuntil(stdout_read, "\n") + readuntil(stdout_read, "\n") + @test pwd() == realpath(tmpdir) + write(stdin_write, ";") + readuntil(stdout_read, "shell> ") + write(stdin_write, "cd -\n") + readuntil(stdout_read, origpwd[max(1,end-39):end]) + readuntil(stdout_read, "\n") + readuntil(stdout_read, "\n") + @test pwd() == origpwd + write(stdin_write, ";") + readuntil(stdout_read, "shell> ") + write(stdin_write, "cd\n") + readuntil(stdout_read, homedir()[max(1,end-39):end]) + readuntil(stdout_read, "\n") + readuntil(stdout_read, "\n") + @test pwd() == homedir() + rm(tmpdir) + cd(origpwd) + + # Test that accepting a REPL result immediately shows up, not + # just on the next keystroke + write(stdin_write, "1+1\n") # populate history with a trivial input + readline(stdout_read) + write(stdin_write, "\e[A\n") + t = Timer(10) do t + isopen(t) || return + error("Stuck waiting for the repl to write `1+1`") + end + # yield make sure this got processed + readuntil(stdout_read, "1+1") + close(t) + + # Issue #10222 + # Test ignoring insert key in standard and prefix search modes + write(stdin_write, "\e[2h\e[2h\n") # insert (VT100-style) + @test search(readline(stdout_read), "[2h") == 0:-1 + readline(stdout_read) + write(stdin_write, "\e[2~\e[2~\n") # insert (VT220-style) + @test search(readline(stdout_read), "[2~") == 0:-1 + readline(stdout_read) + write(stdin_write, "1+1\n") # populate history with a trivial input + readline(stdout_read) + write(stdin_write, "\e[A\e[2h\n") # up arrow, insert (VT100-style) + readline(stdout_read) + readline(stdout_read) + write(stdin_write, "\e[A\e[2~\n") # up arrow, insert (VT220-style) + readline(stdout_read) + readline(stdout_read) + + # Close REPL ^D + write(stdin_write, '\x04') + wait(repltask) end function buffercontents(buf::IOBuffer) @@ -346,41 +346,40 @@ let exename = joinpath(JULIA_HOME, Base.julia_exename()) # Test REPL in dumb mode @unix_only begin - -const O_RDWR = Base.FS.JL_O_RDWR -const O_NOCTTY = Base.FS.JL_O_NOCTTY - -fdm = ccall(:posix_openpt,Cint,(Cint,),O_RDWR|O_NOCTTY) -fdm == -1 && error("Failed to open PTY master") -rc = ccall(:grantpt,Cint,(Cint,),fdm) -rc != 0 && error("grantpt failed") -rc = ccall(:unlockpt,Cint,(Cint,),fdm) -rc != 0 && error("unlockpt") - -fds = ccall(:open,Cint,(Ptr{UInt8},Cint),ccall(:ptsname,Ptr{UInt8},(Cint,),fdm), O_RDWR|O_NOCTTY) - -# slave -slave = RawFD(fds) -master = Base.TTY(RawFD(fdm); readable = true) - -nENV = copy(ENV) -nENV["TERM"] = "dumb" -p = spawn(setenv(`$exename --startup-file=no --quiet`,nENV),slave,slave,slave) -output = readuntil(master,"julia> ") -if ccall(:jl_running_on_valgrind,Cint,()) == 0 - # If --trace-children=yes is passed to valgrind, we will get a - # valgrind banner here, not just the prompt. - @test output == "julia> " -end -write(master,"1\nquit()\n") - -wait(p) -output = readuntil(master,' ') -@test output == "1\r\nquit()\r\n1\r\n\r\njulia> " -@test nb_available(master) == 0 -ccall(:close,Cint,(Cint,),fds) # XXX: this causes the kernel to throw away all unread data on the pty -close(master) - + const O_RDWR = Base.FS.JL_O_RDWR + const O_NOCTTY = Base.FS.JL_O_NOCTTY + + fdm = ccall(:posix_openpt, Cint, (Cint,), O_RDWR|O_NOCTTY) + fdm == -1 && error("Failed to open PTY master") + rc = ccall(:grantpt, Cint, (Cint,), fdm) + rc != 0 && error("grantpt failed") + rc = ccall(:unlockpt, Cint, (Cint,), fdm) + rc != 0 && error("unlockpt") + + fds = ccall(:open, Cint, (Ptr{UInt8}, Cint), + ccall(:ptsname, Ptr{UInt8}, (Cint,), fdm), O_RDWR|O_NOCTTY) + + # slave + slave = RawFD(fds) + master = Base.TTY(RawFD(fdm); readable = true) + + nENV = copy(ENV) + nENV["TERM"] = "dumb" + p = spawn(setenv(`$exename --startup-file=no --quiet`,nENV),slave,slave,slave) + output = readuntil(master,"julia> ") + if ccall(:jl_running_on_valgrind,Cint,()) == 0 + # If --trace-children=yes is passed to valgrind, we will get a + # valgrind banner here, not just the prompt. + @test output == "julia> " + end + write(master,"1\nquit()\n") + + wait(p) + output = readuntil(master,' ') + @test output == "1\r\nquit()\r\n1\r\n\r\njulia> " + @test nb_available(master) == 0 + ccall(:close,Cint,(Cint,),fds) # XXX: this causes the kernel to throw away all unread data on the pty + close(master) end # Test stream mode diff --git a/test/show.jl b/test/show.jl index 80f473abdd6d1..38ff1a1b5118d 100644 --- a/test/show.jl +++ b/test/show.jl @@ -322,3 +322,35 @@ if isempty(Base.GIT_VERSION_INFO.commit) else @test contains(Base.url(methods(eigs).defs),"https://github.com/JuliaLang/julia/tree/$(Base.GIT_VERSION_INFO.commit)/base/linalg/arnoldi.jl#L") end + +# print_matrix should be able to handle small and large objects easily, test by +# calling writemime. This also indirectly tests print_matrix_row, which +# is used repeatedly by print_matrix. +# This fits on screen: +@test replstr(eye(10)) == "10x10 Array{Float64,2}:\n 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0\n 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0\n 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0\n 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0\n 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0\n 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0\n 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0" +# an array too long vertically to fit on screen, and too long horizontally: +@test replstr(collect(1.:100.)) == "100-element Array{Float64,1}:\n 1.0\n 2.0\n 3.0\n 4.0\n 5.0\n 6.0\n 7.0\n 8.0\n 9.0\n 10.0\n ⋮ \n 92.0\n 93.0\n 94.0\n 95.0\n 96.0\n 97.0\n 98.0\n 99.0\n 100.0" +@test replstr(collect(1.:100.)') == "1x100 Array{Float64,2}:\n 1.0 2.0 3.0 4.0 5.0 6.0 7.0 … 95.0 96.0 97.0 98.0 99.0 100.0" +# too big in both directions to fit on screen: +@test replstr((1.:100.)*(1:100)') == "100x100 Array{Float64,2}:\n 1.0 2.0 3.0 4.0 5.0 6.0 … 97.0 98.0 99.0 100.0\n 2.0 4.0 6.0 8.0 10.0 12.0 194.0 196.0 198.0 200.0\n 3.0 6.0 9.0 12.0 15.0 18.0 291.0 294.0 297.0 300.0\n 4.0 8.0 12.0 16.0 20.0 24.0 388.0 392.0 396.0 400.0\n 5.0 10.0 15.0 20.0 25.0 30.0 485.0 490.0 495.0 500.0\n 6.0 12.0 18.0 24.0 30.0 36.0 … 582.0 588.0 594.0 600.0\n 7.0 14.0 21.0 28.0 35.0 42.0 679.0 686.0 693.0 700.0\n 8.0 16.0 24.0 32.0 40.0 48.0 776.0 784.0 792.0 800.0\n 9.0 18.0 27.0 36.0 45.0 54.0 873.0 882.0 891.0 900.0\n 10.0 20.0 30.0 40.0 50.0 60.0 970.0 980.0 990.0 1000.0\n ⋮ ⋮ ⋱ \n 92.0 184.0 276.0 368.0 460.0 552.0 8924.0 9016.0 9108.0 9200.0\n 93.0 186.0 279.0 372.0 465.0 558.0 9021.0 9114.0 9207.0 9300.0\n 94.0 188.0 282.0 376.0 470.0 564.0 9118.0 9212.0 9306.0 9400.0\n 95.0 190.0 285.0 380.0 475.0 570.0 9215.0 9310.0 9405.0 9500.0\n 96.0 192.0 288.0 384.0 480.0 576.0 … 9312.0 9408.0 9504.0 9600.0\n 97.0 194.0 291.0 388.0 485.0 582.0 9409.0 9506.0 9603.0 9700.0\n 98.0 196.0 294.0 392.0 490.0 588.0 9506.0 9604.0 9702.0 9800.0\n 99.0 198.0 297.0 396.0 495.0 594.0 9603.0 9702.0 9801.0 9900.0\n 100.0 200.0 300.0 400.0 500.0 600.0 9700.0 9800.0 9900.0 10000.0" + +# issue #15309 +l1, l2, l2n = Expr(:line,42), Expr(:line,42,:myfile), LineNumberNode(:myfile,42) +@test string(l2n) == " # myfile, line 42:" +@test string(l2) == string(l2n) +@test string(l1) == replace(string(l2n),"myfile, ","",1) +ex = Expr(:block, l1, :x, l2, :y, l2n, :z) +@test replace(string(ex)," ","") == replace(""" +begin # line 42: + x # myfile, line 42: + y # myfile, line 42: + z +end""", " ", "") +# Test the printing of whatever form of line number representation +# that is used in the arguments to a macro looks the same as for +# regular quoting +macro strquote(ex) + QuoteNode(string(ex)) +end +str_ex2a, str_ex2b = @strquote(begin x end), string(quote x end) +@test str_ex2a == str_ex2b diff --git a/test/socket.jl b/test/socket.jl index b1f9d367515e4..947aa57e9722d 100644 --- a/test/socket.jl +++ b/test/socket.jl @@ -188,3 +188,24 @@ if @unix? true : (Base.windows_version() >= Base.WINDOWS_VISTA_VER) send(b, ip"::1", port, "Hello World") wait(tsk) end + +let P = Pipe() + Base.link_pipe(P) + write(P, "hello") + @test nb_available(P) == 0 + @test !eof(P) + @test read(P, Char) === 'h' + @test !eof(P) + @test read(P, Char) === 'e' + @test isopen(P) + close(P.in) + @test isopen(P) + @test !eof(P) + @test readuntil(P, 'o') == "llo" + @test isopen(P) + @test eof(P) + @test !isopen(P) + close(P) + @test !isopen(P) + @test eof(P) +end diff --git a/test/sparsedir/cholmod.jl b/test/sparsedir/cholmod.jl index 97a5802d98980..706c655ece629 100644 --- a/test/sparsedir/cholmod.jl +++ b/test/sparsedir/cholmod.jl @@ -621,3 +621,7 @@ Fnew = deserialize(b) @test_throws ArgumentError diag(Fnew) @test_throws ArgumentError logdet(Fnew) +# Issue with promotion during conversion to CHOLMOD.Dense +@test SparseMatrix.CHOLMOD.Dense(ones(Float32, 5)) == ones(5, 1) +@test SparseMatrix.CHOLMOD.Dense(ones(Int, 5)) == ones(5, 1) +@test SparseMatrix.CHOLMOD.Dense(ones(Complex{Float32}, 5, 2)) == ones(5, 2) diff --git a/test/sparsedir/umfpack.jl b/test/sparsedir/umfpack.jl index 8f436cdca50f6..b6b6df14db85c 100644 --- a/test/sparsedir/umfpack.jl +++ b/test/sparsedir/umfpack.jl @@ -62,3 +62,5 @@ x = speye(2) + im * speye(2) @test det(sparse([1,3,3,1], [1,1,3,3], [1,1,1,1])) == 0 +# UMFPACK_ERROR_n_nonpositive +@test_throws ArgumentError lufact(sparse(Int[], Int[], Float64[], 5, 0))