Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: backports for 1.0.5 #32263

Closed
wants to merge 10 commits into from
9 changes: 7 additions & 2 deletions base/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,13 @@ We can see the [`mtime`](@ref) has been modified by `touch`.
function touch(path::AbstractString)
f = open(path, JL_O_WRONLY | JL_O_CREAT, 0o0666)
try
t = time()
futime(f,t,t)
if Sys.isunix()
ret = ccall(:futimes, Cint, (Cint, Ptr{Cvoid}), fd(f), C_NULL)
systemerror(:futimes, ret != 0, extrainfo=path)
else
t = time()
futime(f,t,t)
end
finally
close(f)
end
Expand Down
14 changes: 10 additions & 4 deletions base/filesystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,19 @@ function close(f::File)
return nothing
end

# sendfile is the most efficient way to copy a file (or any file descriptor)
# sendfile is the most efficient way to copy from a file descriptor
function sendfile(dst::File, src::File, src_offset::Int64, bytes::Int)
check_open(dst)
check_open(src)
err = ccall(:jl_fs_sendfile, Int32, (OS_HANDLE, OS_HANDLE, Int64, Csize_t),
src.handle, dst.handle, src_offset, bytes)
uv_error("sendfile", err)
while true
result = ccall(:jl_fs_sendfile, Int32, (OS_HANDLE, OS_HANDLE, Int64, Csize_t),
src.handle, dst.handle, src_offset, bytes)
uv_error("sendfile", result)
nsent = result
bytes -= nsent
src_offset += nsent
bytes <= 0 && break
end
nothing
end

Expand Down
17 changes: 10 additions & 7 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -503,15 +503,18 @@ for Ti in (Int64,UInt64,Int128,UInt128)
end
end
end
for op in (:(==), :<, :<=)
@eval begin
($op)(x::Float16, y::Union{Int128,UInt128,Int64,UInt64}) = ($op)(Float64(x), Float64(y))
($op)(x::Union{Int128,UInt128,Int64,UInt64}, y::Float16) = ($op)(Float64(x), Float64(y))

==(x::Float32, y::Union{Int32,UInt32}) = Float64(x)==Float64(y)
==(x::Union{Int32,UInt32}, y::Float32) = Float64(x)==Float64(y)

<(x::Float32, y::Union{Int32,UInt32}) = Float64(x)<Float64(y)
<(x::Union{Int32,UInt32}, y::Float32) = Float64(x)<Float64(y)
($op)(x::Union{Float16,Float32}, y::Union{Int32,UInt32}) = ($op)(Float64(x), Float64(y))
($op)(x::Union{Int32,UInt32}, y::Union{Float16,Float32}) = ($op)(Float64(x), Float64(y))

<=(x::Float32, y::Union{Int32,UInt32}) = Float64(x)<=Float64(y)
<=(x::Union{Int32,UInt32}, y::Float32) = Float64(x)<=Float64(y)
($op)(x::Float16, y::Union{Int16,UInt16}) = ($op)(Float32(x), Float32(y))
($op)(x::Union{Int16,UInt16}, y::Float16) = ($op)(Float32(x), Float32(y))
end
end


abs(x::Float16) = reinterpret(Float16, reinterpret(UInt16, x) & 0x7fff)
Expand Down
5 changes: 0 additions & 5 deletions src/flisp/system.lsp
Original file line number Diff line number Diff line change
Expand Up @@ -611,11 +611,6 @@
#;(define (table.values t)
(table.foldl (lambda (k v z) (cons v z))
() t))
#;(define (table.clone t)
(let ((nt (table)))
(table.foldl (lambda (k v z) (put! nt k v))
() t)
nt))
#;(define (table.invert t)
(let ((nt (table)))
(table.foldl (lambda (k v z) (put! nt v k))
Expand Down
132 changes: 64 additions & 68 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -2905,19 +2905,6 @@ f(x) = yt(x)
(or (assq s (car (lam:vinfo lam)))
(assq s (cadr (lam:vinfo lam)))))

(define (table.merge! l r)
(table.foreach (lambda (k v) (put! l k v))
r))

(define (table.delete-if! p t)
(let ((to-del '()))
(table.foreach (lambda (v _)
(if (p v)
(set! to-del (cons v to-del))))
t)
(for-each (lambda (v) (del! t v))
to-del)))

;; Try to identify never-undef variables, and then clear the `captured` flag for single-assigned,
;; never-undef variables to avoid allocating unnecessary `Box`es.
(define (lambda-optimize-vars! lam)
Expand All @@ -2931,81 +2918,90 @@ f(x) = yt(x)
(let ((am (all-methods-for ex stmts)))
(put! allmethods-table mn am)
am))))
(define (expr-uses-var ex v body)
(cond ((atom? ex) (expr-contains-eq v ex))
((assignment? ex) (expr-contains-eq v (caddr ex)))
((eq? (car ex) 'method)
(and (length> ex 2)
;; a method expression captures a variable if any methods for the
;; same function do.
(let* ((mn (method-expr-name ex))
(all-methods (if (local-in? mn lam)
(get-methods ex body)
(list ex))))
(any (lambda (ex)
(assq v (cadr (lam:vinfo (cadddr ex)))))
all-methods))))
(else (expr-contains-eq v ex))))
;; This does a basic-block-local dominance analysis to find variables that
;; are never used undef.
(let ((vi (car (lam:vinfo lam)))
(unused (table)) ;; variables not (yet) used (read from) in the current block
(live (table)) ;; variables that have been set in the current block
(seen (table)) ;; all variables we've seen assignments to
(b1vars '()) ;; vars set in first basic block
(first #t)) ;; are we in the first basic block?
(seen (table))) ;; all variables we've seen assignments to
;; Collect candidate variables: those that are captured (and hence we want to optimize)
;; and only assigned once. This populates the initial `unused` table.
(for-each (lambda (v)
(if (and (vinfo:capt v) (vinfo:sa v))
(put! unused (car v) #t)))
vi)
(define (restore old)
(table.foreach (lambda (k v)
(if (not (has? old k))
(put! unused k v)))
live)
(set! live old))
(define (kill)
;; when we see control flow, empty live set back into unused set
(if first
(begin (set! first #f)
(set! b1vars (table.keys live))))
(table.merge! unused live)
(set! live (table)))
(define (mark-used e)
;; remove variables used by `e` from the unused table
(table.delete-if! (lambda (v) (expr-uses-var e v (lam:body lam)))
unused))
(restore (table)))
(define (mark-used var)
;; remove variable from the unused table
(if (has? unused var)
(del! unused var)))
(define (assign! var)
(if (has? unused var)
;; When a variable is assigned, move it to the live set to protect
;; it from being removed from `unused`.
(begin (put! live var #t)
(put! seen var #t)
(del! unused var))))
(define (visit e)
(cond ((atom? e) (if (symbol? e) (mark-used e)))
;; returns whether e contained a symboliclabel
(cond ((atom? e) (if (symbol? e) (mark-used e))
#f)
((lambda-opt-ignored-exprs (car e))
#t)
#f)
((eq? (car e) 'scope-block)
(visit (cadr e)))
((eq? (car e) 'block)
(for-each visit (cdr e)))
((memq (car e) '(block call new _do_while))
(eager-any visit (cdr e)))
((eq? (car e) 'break-block)
(visit (caddr e)))
((eq? (car e) 'return)
(visit (cadr e))
(kill))
((memq (car e) '(break label symboliclabel symbolicgoto))
(kill))
((memq (car e) '(if elseif _while _do_while trycatch tryfinally))
(for-each (lambda (e)
(visit e)
(kill))
(cdr e)))
(begin0 (visit (cadr e))
(kill)))
((memq (car e) '(break label symbolicgoto))
(kill)
#f)
((eq? (car e) 'symboliclabel)
(kill)
#t)
((memq (car e) '(if elseif _while trycatch tryfinally))
(let ((prev (table.clone live)))
(if (eager-any (lambda (e) (begin0 (visit e)
(kill)))
(cdr e))
;; if there is a label inside, we could have skipped a prior
;; variable initialization
(begin (kill) #t)
(begin (restore prev) #f))))
((eq? (car e) '=)
(begin0 (visit (caddr e))
(assign! (cadr e))))
((eq? (car e) 'method)
(if (length> e 2)
(let* ((mn (method-expr-name e))
;; a method expression captures a variable if any methods for
;; the same function do.
(all-methods (if (local-in? mn lam)
(get-methods e (lam:body lam))
(list e))))
(for-each (lambda (ex)
(for-each mark-used
(map car (cadr (lam:vinfo (cadddr ex))))))
all-methods)
(assign! (cadr e))))
#f)
(else
(if (eq? (car e) '=)
(visit (caddr e))
(mark-used e))
(if (and (or (eq? (car e) '=)
(and (eq? (car e) 'method) (length> e 2)))
(has? unused (cadr e)))
;; When a variable is assigned, move it to the live set to protect
;; it from being removed from `unused`.
(begin (put! live (cadr e) #t)
(put! seen (cadr e) #t)
(del! unused (cadr e)))
;; in all other cases there's nothing to do except assert that
;; all expression heads have been handled.
#;(assert (memq (car e) '(= method new call foreigncall cfunction |::|)))))))
(eager-any visit (cdr e))
;; in all other cases there's nothing to do except assert that
;; all expression heads have been handled.
#;(assert (memq (car e) '(foreigncall cfunction |::|))))))
(visit (lam:body lam))
;; Finally, variables can be marked never-undef if they were set in the first block,
;; or are currently live, or are back in the unused set (because we've left the only
Expand All @@ -3014,7 +3010,7 @@ f(x) = yt(x)
(if (has? seen v)
(let ((vv (assq v vi)))
(vinfo:set-never-undef! vv #t))))
(append b1vars (table.keys live) (table.keys unused)))
(append (table.keys live) (table.keys unused)))
(for-each (lambda (v)
(if (and (vinfo:sa v) (vinfo:never-undef v))
(set-car! (cddr v) (logand (caddr v) (lognot 5)))))
Expand Down
2 changes: 1 addition & 1 deletion src/llvm-late-gc-lowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,9 +821,9 @@ void LateLowerGCFrame::NoteUse(State &S, BBState &BBS, Value *V, BitVector &Uses
else if (isSpecialPtrVec(V->getType())) {
std::vector<int> Nums = NumberVector(S, V);
for (int Num : Nums) {
MaybeResize(BBS, Num);
if (Num < 0)
continue;
MaybeResize(BBS, Num);
Uses[Num] = 1;
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/macroexpand.scm
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,14 @@
(body (cadr e))
(m (caddr e)))
(resolve-expansion-vars-with-new-env body env m parent-scope inarg #t)))
((tuple)
(cons (car e)
(map (lambda (x)
(if (assignment? x)
`(= ,(unescape (cadr x))
,(resolve-expansion-vars-with-new-env x env m parent-scope inarg))
(resolve-expansion-vars-with-new-env x env m parent-scope inarg)))
(cdr e))))

;; todo: trycatch
(else
Expand Down
16 changes: 12 additions & 4 deletions src/subtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -1264,10 +1264,18 @@ JL_DLLEXPORT int jl_isa(jl_value_t *x, jl_value_t *t)
if (((jl_datatype_t*)t2)->name == jl_type_typename) {
jl_value_t *tp = jl_tparam0(t2);
if (jl_is_typevar(tp)) {
while (jl_is_typevar(tp))
tp = ((jl_tvar_t*)tp)->ub;
if (!jl_has_free_typevars(tp))
return jl_subtype(x, tp);
if (((jl_tvar_t*)tp)->lb == jl_bottom_type) {
while (jl_is_typevar(tp))
tp = ((jl_tvar_t*)tp)->ub;
if (!jl_has_free_typevars(tp))
return jl_subtype(x, tp);
}
else if (((jl_tvar_t*)tp)->ub == (jl_value_t*)jl_any_type) {
while (jl_is_typevar(tp))
tp = ((jl_tvar_t*)tp)->lb;
if (!jl_has_free_typevars(tp))
return jl_subtype(tp, x);
}
}
}
else {
Expand Down
15 changes: 15 additions & 0 deletions src/utils.scm
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,18 @@
(without (cdr alst) remove)))))

(define (caddddr x) (car (cdr (cdr (cdr (cdr x))))))

(define (table.clone t)
(let ((nt (table)))
(table.foldl (lambda (k v z) (put! nt k v))
() t)
nt))

;; `any`, but call predicate on every element in order no matter what
(define (eager-any pred lst)
(let loop ((lst lst)
(any #f))
(if (null? lst)
any
(loop (cdr lst)
(or (pred (car lst)) any)))))
2 changes: 1 addition & 1 deletion stdlib/Distributed/src/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ Equivalent to calling `remotecall_eval(Main, procs, expr)`.
"""
macro everywhere(ex)
procs = GlobalRef(@__MODULE__, :procs)
return esc(:(@everywhere $procs() $ex))
return esc(:($(Distributed).@everywhere $procs() $ex))
end

macro everywhere(procs, ex)
Expand Down
12 changes: 12 additions & 0 deletions stdlib/Distributed/test/distributed_exec.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,18 @@ for T in (UInt8, Int8, UInt16, Int16, UInt32, Int32, UInt64)
@test n == 55
end

# issue #28966
let code = """
import Distributed
Distributed.addprocs(1)
Distributed.@everywhere f() = myid()
for w in Distributed.workers()
@assert Distributed.remotecall_fetch(f, w) == w
end
"""
@test success(`$(Base.julia_cmd()) --startup-file=no -e $code`)
end

# Run topology tests last after removing all workers, since a given
# cluster at any time only supports a single topology.
rmprocs(workers())
Expand Down
2 changes: 1 addition & 1 deletion stdlib/LibGit2/test/online.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ mktempdir() do dir
error("unexpected")
catch ex
@test isa(ex, LibGit2.Error.GitError)
@test ex.code == LibGit2.Error.EAUTH
@test ex.code == LibGit2.Error.ERROR
end
Base.shred!(cred)
end
Expand Down
8 changes: 4 additions & 4 deletions stdlib/LinearAlgebra/test/diagonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -450,10 +450,10 @@ end
M = randn(T, 5, 5)
MM = [randn(T, 2, 2) for _ in 1:2, _ in 1:2]
for transform in (identity, adjoint, transpose, Adjoint, Transpose)
@test lmul!(transform(D), copy(M)) == *(transform(Matrix(D)), M)
@test rmul!(copy(M), transform(D)) == *(M, transform(Matrix(D)))
@test lmul!(transform(DD), copy(MM)) == *(transform(fullDD), MM)
@test rmul!(copy(MM), transform(DD)) == *(MM, transform(fullDD))
@test lmul!(transform(D), copy(M)) *(transform(Matrix(D)), M)
@test rmul!(copy(M), transform(D)) *(M, transform(Matrix(D)))
@test lmul!(transform(DD), copy(MM)) *(transform(fullDD), MM)
@test rmul!(copy(MM), transform(DD)) *(MM, transform(fullDD))
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions test/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,15 @@ function inbounds_30563()
end
@test Base.return_types(inbounds_30563, ()) == Any[Int]

function ifs_around_var_capture()
if false end
x = 1
if false end
f = y->x
f(0)
end
@test Base.return_types(ifs_around_var_capture, ()) == Any[Int]

# issue #27316 - inference shouldn't hang on these
f27316(::Vector) = nothing
f27316(::Any) = f27316(Any[][1]), f27316(Any[][1])
Expand Down
Loading