Skip to content

Commit b0c5f61

Browse files
authored
Backports 1.12 (#57408)
Backported PRs: - [x] #57346 <!-- lowering: Only try to define the method once --> - [x] #57341 <!-- bpart: When backdating replace the entire bpart chain --> - [x] #57381 <!-- staticdata: Set min validation world to require world --> - [x] #57357 <!-- Only implicitly `using` Base, not Core --> - [x] #57383 <!-- staticdata: Fix typo in recursive edge revalidation --> - [x] #57385 <!-- bpart: Move kind enum into its intended place --> - [x] #57275 <!-- Compiler: fix unsoundness of getfield_tfunc on Tuple Types --> - [x] #57378 <!-- print admonition for auto-import only once per module --> - [x] #57392 <!-- [LateLowerGCFrame] fix PlaceGCFrameReset for returns_twice --> - [x] #57388 <!-- Bump JuliaSyntax to v1.0.2 --> - [x] #57266 <!-- 🤖 [master] Bump the Statistics stdlib from d49c2bf to 77bd570 --> - [x] #57395 <!-- lowering: fix has_fcall computation --> - [x] #57204 <!-- Clarify mathematical definition of `gcd` --> - [x] #56794 <!-- Make `Pairs` public --> - [x] #57407 <!-- staticdata: corrected implementation of jl_collect_new_roots --> - [x] #57405 <!-- bpart: Also partition the export flag --> - [x] #57420 <!-- Compiler: Fix check for IRShow definedness --> - [x] #55875 <!-- fix `(-Inf)^-1` inconsistency --> - [x] #57317 <!-- internals: add _defaultctor function for defining ctors --> - [x] #57406 <!-- bpart: Ignore guard bindings for ambiguity purposes --> - [x] #49933 <!-- Allow for :foreigncall to transition to GC safe automatically -->
2 parents 08d3c70 + 5da257d commit b0c5f61

Some content is hidden

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

62 files changed

+993
-697
lines changed

Compiler/src/abstractinterpretation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3409,7 +3409,7 @@ function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, sstate:
34093409
abstract_eval_value(interp, x, sstate, sv)
34103410
end
34113411
cconv = e.args[5]
3412-
if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt16}))
3412+
if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt16, Bool}))
34133413
override = decode_effects_override(v[2])
34143414
effects = override_effects(effects, override)
34153415
end

Compiler/src/ssair/verify.jl

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

3+
irshow_was_loaded() = invokelatest(isdefined, Compiler.IRShow, :debuginfo_firstline)
34
function maybe_show_ir(ir::IRCode)
4-
if isdefined(Core, :Main) && isdefined(Core.Main, :Base)
5+
if irshow_was_loaded()
56
# ensure we use I/O that does not yield, as this gets called during compilation
67
invokelatest(Core.Main.Base.show, Core.stdout, "text/plain", ir)
78
else
@@ -104,15 +105,16 @@ function count_int(val::Int, arr::Vector{Int})
104105
n
105106
end
106107

108+
_debuginfo_firstline(debuginfo::Union{DebugInfo,DebugInfoStream}) = IRShow.debuginfo_firstline(debuginfo)
107109
function verify_ir(ir::IRCode, print::Bool=true,
108110
allow_frontend_forms::Bool=false,
109111
𝕃ₒ::AbstractLattice = SimpleInferenceLattice.instance,
110112
mi::Union{Nothing,MethodInstance}=nothing)
111113
function raise_error()
112114
error_args = Any["IR verification failed."]
113-
if isdefined(Core, :Main) && isdefined(Core.Main, :Base)
115+
if irshow_was_loaded()
114116
# ensure we use I/O that does not yield, as this gets called during compilation
115-
firstline = invokelatest(IRShow.debuginfo_firstline, ir.debuginfo)
117+
firstline = invokelatest(_debuginfo_firstline, ir.debuginfo)
116118
else
117119
firstline = nothing
118120
end

Compiler/src/typeinfer.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ being used for this purpose alone.
1010
"""
1111
module Timings
1212

13+
using ..Core
1314
using ..Compiler: -, +, :, Vector, length, first, empty!, push!, pop!, @inline,
1415
@inbounds, copy, backtrace
1516

Compiler/src/typeutils.jl

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,8 @@ function isTypeDataType(@nospecialize t)
3636
isType(t) && return false
3737
# Could be Union{} at runtime
3838
t === Core.TypeofBottom && return false
39-
if t.name === Tuple.name
40-
# If we have a Union parameter, could have been redistributed at runtime,
41-
# e.g. `Tuple{Union{Int, Float64}, Int}` is a DataType, but
42-
# `Union{Tuple{Int, Int}, Tuple{Float64, Int}}` is typeequal to it and
43-
# is not.
44-
return all(isTypeDataType, t.parameters)
45-
end
46-
return true
39+
# Return true if `t` is not covariant
40+
return t.name !== Tuple.name
4741
end
4842

4943
has_extended_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isType(x)

Compiler/src/validation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const VALID_EXPR_HEADS = IdDict{Symbol,UnitRange{Int}}(
2323
:meta => 0:typemax(Int),
2424
:global => 1:1,
2525
:globaldecl => 1:2,
26-
:foreigncall => 5:typemax(Int), # name, RT, AT, nreq, (cconv, effects), args..., roots...
26+
:foreigncall => 5:typemax(Int), # name, RT, AT, nreq, (cconv, effects, gc_safe), args..., roots...
2727
:cfunction => 5:5,
2828
:isdefined => 1:2,
2929
:code_coverage_effect => 0:0,

Compiler/test/inline.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,7 @@ let getfield_tfunc(@nospecialize xs...) =
17691769
Compiler.getfield_tfunc(Compiler.fallback_lattice, xs...)
17701770
@test getfield_tfunc(Type, Core.Const(:parameters)) !== Union{}
17711771
@test !isa(getfield_tfunc(Type{Tuple{Union{Int, Float64}, Int}}, Core.Const(:name)), Core.Const)
1772+
@test !isa(getfield_tfunc(Type{Tuple{Any}}, Core.Const(:name)), Core.Const)
17721773
end
17731774
@test fully_eliminated(Base.ismutable, Tuple{Base.RefValue})
17741775

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ New language features
2525
* Support for Unicode 16 ([#56925]).
2626
* `Threads.@spawn` now takes a `:samepool` argument to specify the same threadpool as the caller.
2727
`Threads.@spawn :samepool foo()` which is shorthand for `Threads.@spawn Threads.threadpool() foo()` ([#57109]).
28+
* The `@ccall` macro can now take a `gc_safe` argument, that if set to true allows the runtime to run garbage collection concurrently to the `ccall`
2829

2930
Language changes
3031
----------------

base/Base_compiler.jl

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

33
baremodule Base
44

5+
using Core
56
using Core.Intrinsics, Core.IR
67

78
# to start, we're going to use a very simple definition of `include`
@@ -135,14 +136,16 @@ include("coreio.jl")
135136

136137
import Core: @doc, @__doc__, WrappedException, @int128_str, @uint128_str, @big_str, @cmd
137138

139+
# Export list
140+
include("exports.jl")
141+
138142
# core docsystem
139143
include("docs/core.jl")
140144
Core.atdoc!(CoreDocs.docm)
141145

142146
eval(x) = Core.eval(Base, x)
143147
eval(m::Module, x) = Core.eval(m, x)
144148

145-
include("exports.jl")
146149
include("public.jl")
147150

148151
if false

base/boot.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,9 @@ export
238238
# method reflection
239239
applicable, invoke,
240240
# constants
241-
nothing, Main
241+
nothing, Main,
242+
# backwards compatibility
243+
arrayref, arrayset, arraysize, const_arrayref
242244

243245
const getproperty = getfield # TODO: use `getglobal` for modules instead
244246
const setproperty! = setfield!
@@ -1040,7 +1042,6 @@ const_arrayref(inbounds::Bool, A::Array, i::Int...) = Main.Base.getindex(A, i...
10401042
arrayset(inbounds::Bool, A::Array{T}, x::Any, i::Int...) where {T} = Main.Base.setindex!(A, x::T, i...)
10411043
arraysize(a::Array) = a.size
10421044
arraysize(a::Array, i::Int) = sle_int(i, nfields(a.size)) ? getfield(a.size, i) : 1
1043-
export arrayref, arrayset, arraysize, const_arrayref
10441045
const check_top_bit = check_sign_bit
10451046

10461047
# For convenience

base/c.jl

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,31 @@ The above input outputs this:
268268
269269
(:printf, :Cvoid, [:Cstring, :Cuint], ["%d", :value])
270270
"""
271-
function ccall_macro_parse(expr::Expr)
271+
function ccall_macro_parse(exprs)
272+
gc_safe = false
273+
expr = nothing
274+
if exprs isa Expr
275+
expr = exprs
276+
elseif length(exprs) == 1
277+
expr = exprs[1]
278+
elseif length(exprs) == 2
279+
gc_expr = exprs[1]
280+
expr = exprs[2]
281+
if gc_expr.head == :(=) && gc_expr.args[1] == :gc_safe
282+
if gc_expr.args[2] == true
283+
gc_safe = true
284+
elseif gc_expr.args[2] == false
285+
gc_safe = false
286+
else
287+
throw(ArgumentError("gc_safe must be true or false"))
288+
end
289+
else
290+
throw(ArgumentError("@ccall option must be `gc_safe=true` or `gc_safe=false`"))
291+
end
292+
else
293+
throw(ArgumentError("@ccall needs a function signature with a return type"))
294+
end
295+
272296
# setup and check for errors
273297
if !isexpr(expr, :(::))
274298
throw(ArgumentError("@ccall needs a function signature with a return type"))
@@ -328,12 +352,11 @@ function ccall_macro_parse(expr::Expr)
328352
pusharg!(a)
329353
end
330354
end
331-
332-
return func, rettype, types, args, nreq
355+
return func, rettype, types, args, gc_safe, nreq
333356
end
334357

335358

336-
function ccall_macro_lower(convention, func, rettype, types, args, nreq)
359+
function ccall_macro_lower(convention, func, rettype, types, args, gc_safe, nreq)
337360
statements = []
338361

339362
# if interpolation was used, ensure the value is a function pointer at runtime.
@@ -351,9 +374,15 @@ function ccall_macro_lower(convention, func, rettype, types, args, nreq)
351374
else
352375
func = esc(func)
353376
end
377+
cconv = nothing
378+
if convention isa Tuple
379+
cconv = Expr(:cconv, (convention..., gc_safe), nreq)
380+
else
381+
cconv = Expr(:cconv, (convention, UInt16(0), gc_safe), nreq)
382+
end
354383

355384
return Expr(:block, statements...,
356-
Expr(:call, :ccall, func, Expr(:cconv, convention, nreq), esc(rettype),
385+
Expr(:call, :ccall, func, cconv, esc(rettype),
357386
Expr(:tuple, map(esc, types)...), map(esc, args)...))
358387
end
359388

@@ -404,9 +433,16 @@ Example using an external library:
404433
405434
The string literal could also be used directly before the function
406435
name, if desired `"libglib-2.0".g_uri_escape_string(...`
436+
437+
It's possible to declare the ccall as `gc_safe` by using the `gc_safe = true` option:
438+
@ccall gc_safe=true strlen(s::Cstring)::Csize_t
439+
This allows the garbage collector to run concurrently with the ccall, which can be useful whenever
440+
the `ccall` may block outside of julia.
441+
WARNING: This option should be used with caution, as it can lead to undefined behavior if the ccall
442+
calls back into the julia runtime. (`@cfunction`/`@ccallables` are safe however)
407443
"""
408-
macro ccall(expr)
409-
return ccall_macro_lower(:ccall, ccall_macro_parse(expr)...)
444+
macro ccall(exprs...)
445+
return ccall_macro_lower((:ccall), ccall_macro_parse(exprs)...)
410446
end
411447

412448
macro ccall_effects(effects::UInt16, expr)

0 commit comments

Comments
 (0)