Skip to content

Commit 08d3c70

Browse files
authored
Backports for upcoming 1.12.0(-beta1) (#57258)
Backported PRs: - [x] #57142 <!-- Add reference to time_ns in time --> - [x] #57241 <!-- Handle `waitpid` race condition when `SIGCHLD` is set to `SIG_IGN` --> - [x] #57249 <!-- restore non-freebsd-unix fix for profiling --> - [x] #57211 <!-- Ensure read/readavailable for BufferStream are threadsafe --> - [x] #57262 <!-- edit NEWS for v1.12 --> - [x] #57226 <!-- cfunction: reimplement, as originally planned, for reliable performance --> - [x] #57253 <!-- bpart: Fully switch to partitioned semantics --> - [x] #57273 <!-- fix "Right arrow autocompletes at line end" implementation --> - [x] #57280 <!-- dep: Update JuliaSyntax --> - [x] #57229 <!-- staticdata: Close data race after backedge insertion --> - [x] #57298 <!-- Updating binding version to fix MMTk CI --> - [x] #57248 <!-- improve concurrency safety for `Compiler.finish!` --> - [x] #57312 <!-- Profile.print: de-focus sleeping frames as gray --> - [x] #57289 <!-- Make `OncePerX` subtype `Function` --> - [x] #57310 <!-- Make ptls allocations at least 128 byte aligned --> - [x] #57311 <!-- Add a warning for auto-import of types --> - [x] #57338 <!-- fix typo in Float32 random number generation --> - [x] #57293 <!-- Fix getfield_tfunc when order or boundscheck is Vararg --> - [x] #57349 <!-- docs: fix-up world-age handling for META access --> - [x] #57344 <!-- Add missing type asserts when taking the queue out of the task struct --> - [x] #57348 <!-- 🤖 [master] Bump the SparseArrays stdlib from 212981b to 72c7cac --> - [x] #55040 <!-- Allow macrocall as function sig --> - [x] #57299 <!-- Add missing latestworld after parameterized type alias -->
2 parents 0c1e800 + ebef610 commit 08d3c70

File tree

107 files changed

+3163
-1758
lines changed

Some content is hidden

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

107 files changed

+3163
-1758
lines changed

Compiler/src/Compiler.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstanc
4949

5050
using Base
5151
using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospecializeinfer,
52-
BINDING_KIND_GLOBAL, BINDING_KIND_UNDEF_CONST, BINDING_KIND_BACKDATED_CONST,
52+
BINDING_KIND_GLOBAL, BINDING_KIND_UNDEF_CONST, BINDING_KIND_BACKDATED_CONST, BINDING_KIND_DECLARED,
5353
Base, BitVector, Bottom, Callable, DataTypeFieldDesc,
5454
EffectsOverride, Filter, Generator, IteratorSize, JLOptions, NUM_EFFECTS_OVERRIDES,
5555
OneTo, Ordering, RefValue, SizeUnknown, _NAMEDTUPLE_NAME,

Compiler/src/abstractinterpretation.jl

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3464,14 +3464,7 @@ world_range(ci::CodeInfo) = WorldRange(ci.min_world, ci.max_world)
34643464
world_range(ci::CodeInstance) = WorldRange(ci.min_world, ci.max_world)
34653465
world_range(compact::IncrementalCompact) = world_range(compact.ir)
34663466

3467-
function force_binding_resolution!(g::GlobalRef, world::UInt)
3468-
# Force resolution of the binding
3469-
# TODO: This will go away once we switch over to fully partitioned semantics
3470-
ccall(:jl_force_binding_resolution, Cvoid, (Any, Csize_t), g, world)
3471-
return nothing
3472-
end
3473-
3474-
function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, IncrementalCompact}, retry_after_resolve::Bool=true)
3467+
function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, IncrementalCompact})
34753468
worlds = world_range(src)
34763469
partition = lookup_binding_partition(min_world(worlds), g)
34773470
partition.max_world < max_world(worlds) && return Any
@@ -3480,25 +3473,18 @@ function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode,
34803473
partition = lookup_binding_partition(min_world(worlds), imported_binding)
34813474
partition.max_world < max_world(worlds) && return Any
34823475
end
3483-
if is_some_guard(binding_kind(partition))
3484-
if retry_after_resolve
3485-
# This method is surprisingly hot. For performance, don't ask the runtime to resolve
3486-
# the binding unless necessary - doing so triggers an additional lookup, which though
3487-
# not super expensive is hot enough to show up in benchmarks.
3488-
force_binding_resolution!(g, min_world(worlds))
3489-
return abstract_eval_globalref_type(g, src, false)
3490-
end
3476+
kind = binding_kind(partition)
3477+
if is_some_guard(kind)
34913478
# return Union{}
34923479
return Any
34933480
end
3494-
if is_some_const_binding(binding_kind(partition))
3481+
if is_some_const_binding(kind)
34953482
return Const(partition_restriction(partition))
34963483
end
3497-
return partition_restriction(partition)
3484+
return kind == BINDING_KIND_DECLARED ? Any : partition_restriction(partition)
34983485
end
34993486

35003487
function lookup_binding_partition!(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState)
3501-
force_binding_resolution!(g, get_inference_world(interp))
35023488
partition = lookup_binding_partition(get_inference_world(interp), g)
35033489
update_valid_age!(sv, WorldRange(partition.min_world, partition.max_world))
35043490
partition
@@ -3541,7 +3527,11 @@ function abstract_eval_partition_load(interp::AbstractInterpreter, partition::Co
35413527
return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL, inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE))
35423528
end
35433529

3544-
rt = partition_restriction(partition)
3530+
if kind == BINDING_KIND_DECLARED
3531+
rt = Any
3532+
else
3533+
rt = partition_restriction(partition)
3534+
end
35453535
return RTEffects(rt, UndefVarError, generic_getglobal_effects)
35463536
end
35473537

@@ -3580,7 +3570,7 @@ function global_assignment_binding_rt_exct(interp::AbstractInterpreter, partitio
35803570
elseif is_some_const_binding(kind)
35813571
return Pair{Any,Any}(Bottom, ErrorException)
35823572
end
3583-
ty = partition_restriction(partition)
3573+
ty = kind == BINDING_KIND_DECLARED ? Any : partition_restriction(partition)
35843574
wnewty = widenconst(newty)
35853575
if !hasintersect(wnewty, ty)
35863576
return Pair{Any,Any}(Bottom, TypeError)

Compiler/src/ssair/ir.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ function is_relevant_expr(e::Expr)
581581
:foreigncall, :isdefined, :copyast,
582582
:throw_undef_if_not,
583583
:cfunction, :method, :pop_exception,
584-
:leave,
584+
:leave, :const, :globaldecl,
585585
:new_opaque_closure)
586586
end
587587

Compiler/src/ssair/verify.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int,
6161
raise_error()
6262
end
6363
elseif isa(op, GlobalRef)
64-
force_binding_resolution!(op, min_world(ir.valid_worlds))
6564
bpart = lookup_binding_partition(min_world(ir.valid_worlds), op)
6665
while is_some_imported(binding_kind(bpart)) && max_world(ir.valid_worlds) <= bpart.max_world
6766
imported_binding = partition_restriction(bpart)::Core.Binding

Compiler/src/tfuncs.jl

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,17 +1073,15 @@ end
10731073
end
10741074

10751075
@nospecs function getfield_tfunc(𝕃::AbstractLattice, s00, name, boundscheck_or_order)
1076-
t = isvarargtype(boundscheck_or_order) ? unwrapva(boundscheck_or_order) :
1077-
widenconst(boundscheck_or_order)
1078-
hasintersect(t, Symbol) || hasintersect(t, Bool) || return Bottom
1076+
if !isvarargtype(boundscheck_or_order)
1077+
t = widenconst(boundscheck_or_order)
1078+
hasintersect(t, Symbol) || hasintersect(t, Bool) || return Bottom
1079+
end
10791080
return getfield_tfunc(𝕃, s00, name)
10801081
end
10811082
@nospecs function getfield_tfunc(𝕃::AbstractLattice, s00, name, order, boundscheck)
10821083
hasintersect(widenconst(order), Symbol) || return Bottom
1083-
if isvarargtype(boundscheck)
1084-
t = unwrapva(boundscheck)
1085-
hasintersect(t, Symbol) || hasintersect(t, Bool) || return Bottom
1086-
else
1084+
if !isvarargtype(boundscheck)
10871085
hasintersect(widenconst(boundscheck), Bool) || return Bottom
10881086
end
10891087
return getfield_tfunc(𝕃, s00, name)

Compiler/src/typeinfer.jl

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ If set to `true`, record per-method-instance timings within type inference in th
9292
__set_measure_typeinf(onoff::Bool) = __measure_typeinf__[] = onoff
9393
const __measure_typeinf__ = RefValue{Bool}(false)
9494

95-
function finish!(interp::AbstractInterpreter, caller::InferenceState)
95+
function finish!(interp::AbstractInterpreter, caller::InferenceState, validation_world::UInt)
9696
result = caller.result
9797
opt = result.src
9898
if opt isa OptimizationState
@@ -108,12 +108,7 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState)
108108
ci = result.ci
109109
# if we aren't cached, we don't need this edge
110110
# but our caller might, so let's just make it anyways
111-
if last(result.valid_worlds) >= get_world_counter()
112-
# TODO: this should probably come after all store_backedges (after optimizations) for the entire graph in finish_cycle
113-
# since we should be requiring that all edges first get their backedges set, as a batch
114-
result.valid_worlds = WorldRange(first(result.valid_worlds), typemax(UInt))
115-
end
116-
if last(result.valid_worlds) == typemax(UInt)
111+
if last(result.valid_worlds) >= validation_world
117112
# if we can record all of the backedges in the global reverse-cache,
118113
# we can now widen our applicability in the global cache too
119114
store_backedges(ci, edges)
@@ -202,7 +197,14 @@ function finish_nocycle(::AbstractInterpreter, frame::InferenceState)
202197
if opt isa OptimizationState # implies `may_optimize(caller.interp) === true`
203198
optimize(frame.interp, opt, frame.result)
204199
end
205-
finish!(frame.interp, frame)
200+
validation_world = get_world_counter()
201+
finish!(frame.interp, frame, validation_world)
202+
if isdefined(frame.result, :ci)
203+
# After validation, under the world_counter_lock, set max_world to typemax(UInt) for all dependencies
204+
# (recursively). From that point onward the ordinary backedge mechanism is responsible for maintaining
205+
# validity.
206+
ccall(:jl_promote_ci_to_current, Cvoid, (Any, UInt), frame.result.ci, validation_world)
207+
end
206208
if frame.cycleid != 0
207209
frames = frame.callstack::Vector{AbsIntState}
208210
@assert frames[end] === frame
@@ -236,10 +238,19 @@ function finish_cycle(::AbstractInterpreter, frames::Vector{AbsIntState}, cyclei
236238
optimize(caller.interp, opt, caller.result)
237239
end
238240
end
241+
validation_world = get_world_counter()
242+
cis = CodeInstance[]
239243
for frameid = cycleid:length(frames)
240244
caller = frames[frameid]::InferenceState
241-
finish!(caller.interp, caller)
245+
finish!(caller.interp, caller, validation_world)
246+
if isdefined(caller.result, :ci)
247+
push!(cis, caller.result.ci)
248+
end
242249
end
250+
# After validation, under the world_counter_lock, set max_world to typemax(UInt) for all dependencies
251+
# (recursively). From that point onward the ordinary backedge mechanism is responsible for maintaining
252+
# validity.
253+
ccall(:jl_promote_cis_to_current, Cvoid, (Ptr{CodeInstance}, Csize_t, UInt), cis, length(cis), validation_world)
243254
resize!(frames, cycleid - 1)
244255
return nothing
245256
end
@@ -1266,6 +1277,7 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim::
12661277
tocompile = Vector{CodeInstance}()
12671278
codeinfos = []
12681279
# first compute the ABIs of everything
1280+
latest = true # whether this_world == world_counter()
12691281
for this_world in reverse(sort!(worlds))
12701282
interp = NativeInterpreter(this_world)
12711283
for i = 1:length(methods)
@@ -1278,18 +1290,18 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim::
12781290
# then we want to compile and emit this
12791291
if item.def.primary_world <= this_world <= item.def.deleted_world
12801292
ci = typeinf_ext(interp, item, SOURCE_MODE_NOT_REQUIRED)
1281-
ci isa CodeInstance && !use_const_api(ci) && push!(tocompile, ci)
1293+
ci isa CodeInstance && push!(tocompile, ci)
12821294
end
1283-
elseif item isa SimpleVector
1295+
elseif item isa SimpleVector && latest
12841296
(rt::Type, sig::Type) = item
12851297
# make a best-effort attempt to enqueue the relevant code for the ccallable
12861298
ptr = ccall(:jl_get_specialization1,
12871299
#= MethodInstance =# Ptr{Cvoid}, (Any, Csize_t, Cint),
12881300
sig, this_world, #= mt_cache =# 0)
12891301
if ptr !== C_NULL
1290-
mi = unsafe_pointer_to_objref(ptr)
1302+
mi = unsafe_pointer_to_objref(ptr)::MethodInstance
12911303
ci = typeinf_ext(interp, mi, SOURCE_MODE_NOT_REQUIRED)
1292-
ci isa CodeInstance && !use_const_api(ci) && push!(tocompile, ci)
1304+
ci isa CodeInstance && push!(tocompile, ci)
12931305
end
12941306
# additionally enqueue the ccallable entrypoint / adapter, which implicitly
12951307
# invokes the above ci
@@ -1305,7 +1317,7 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim::
13051317
mi = get_ci_mi(callee)
13061318
def = mi.def
13071319
if use_const_api(callee)
1308-
src = codeinfo_for_const(interp, mi, code.rettype_const)
1320+
src = codeinfo_for_const(interp, mi, callee.rettype_const)
13091321
elseif haskey(interp.codegen, callee)
13101322
src = interp.codegen[callee]
13111323
elseif isa(def, Method) && ccall(:jl_get_module_infer, Cint, (Any,), def.module) == 0 && !trim
@@ -1327,6 +1339,7 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim::
13271339
println("warning: failed to get code for ", mi)
13281340
end
13291341
end
1342+
latest = false
13301343
end
13311344
return codeinfos
13321345
end

Compiler/src/validation.jl

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

Compiler/test/effects.jl

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -378,32 +378,27 @@ let effects = Base.infer_effects(; optimize=false) do
378378
end
379379

380380
# we should taint `nothrow` if the binding doesn't exist and isn't fixed yet,
381-
# as the cached effects can be easily wrong otherwise
382-
# since the inference currently doesn't track "world-age" of global variables
383-
@eval global_assignment_undefinedyet() = $(GlobalRef(@__MODULE__, :UNDEFINEDYET)) = 42
384381
setglobal!_nothrow_undefinedyet() = setglobal!(@__MODULE__, :UNDEFINEDYET, 42)
385-
let effects = Base.infer_effects() do
386-
global_assignment_undefinedyet()
387-
end
382+
let effects = Base.infer_effects(setglobal!_nothrow_undefinedyet)
388383
@test !Compiler.is_nothrow(effects)
389384
end
390-
let effects = Base.infer_effects() do
391-
setglobal!_nothrow_undefinedyet()
392-
end
393-
@test !Compiler.is_nothrow(effects)
385+
@test_throws ErrorException setglobal!_nothrow_undefinedyet()
386+
# This declares the binding as ::Any
387+
@eval global_assignment_undefinedyet() = $(GlobalRef(@__MODULE__, :UNDEFINEDYET)) = 42
388+
let effects = Base.infer_effects(global_assignment_undefinedyet)
389+
@test Compiler.is_nothrow(effects)
394390
end
395-
global UNDEFINEDYET::String = "0"
396-
let effects = Base.infer_effects() do
397-
global_assignment_undefinedyet()
398-
end
391+
# Again with type mismatch
392+
global UNDEFINEDYET2::String = "0"
393+
setglobal!_nothrow_undefinedyet2() = setglobal!(@__MODULE__, :UNDEFINEDYET2, 42)
394+
@eval global_assignment_undefinedyet2() = $(GlobalRef(@__MODULE__, :UNDEFINEDYET2)) = 42
395+
let effects = Base.infer_effects(global_assignment_undefinedyet2)
399396
@test !Compiler.is_nothrow(effects)
400397
end
401-
let effects = Base.infer_effects() do
402-
setglobal!_nothrow_undefinedyet()
403-
end
398+
let effects = Base.infer_effects(setglobal!_nothrow_undefinedyet2)
404399
@test !Compiler.is_nothrow(effects)
405400
end
406-
@test_throws Union{ErrorException,TypeError} setglobal!_nothrow_undefinedyet() # TODO: what kind of error should this be?
401+
@test_throws TypeError setglobal!_nothrow_undefinedyet2()
407402

408403
# Nothrow for setfield!
409404
mutable struct SetfieldNothrow

Compiler/test/inference.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6160,7 +6160,7 @@ end === Int
61606160
swapglobal!(@__MODULE__, :swapglobal!_xxx, x)
61616161
end === Union{}
61626162

6163-
global swapglobal!_must_throw
6163+
eval(Expr(:const, :swapglobal!_must_throw))
61646164
@newinterp SwapGlobalInterp
61656165
Compiler.InferenceParams(::SwapGlobalInterp) = Compiler.InferenceParams(; assume_bindings_static=true)
61666166
function func_swapglobal!_must_throw(x)
@@ -6188,3 +6188,9 @@ end == Union{Float64,DomainError}
61886188
@test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64 ]) === Tuple{Int, UnitRange{Int}, Float64}
61896189
@test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64, Memory{2} ]) === Union{}
61906190
@test Base.return_types(Tuple{Tuple{Int, Vararg{Pair{Any, Union{}}}}},) do x; Returns(true)(x...); end |> only === Bool
6191+
6192+
# issue #57292
6193+
f57292(xs::Union{Tuple{String}, Int}...) = getfield(xs...)
6194+
g57292(xs::String...) = getfield(("abc",), 1, :not_atomic, xs...)
6195+
@test Base.infer_return_type(f57292) == String
6196+
@test Base.infer_return_type(g57292) == String

Makefile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,26 @@ endif
282282
endif
283283

284284
ifneq (${MMTK_PLAN},None)
285+
# Make sure we use the right version of $MMTK_PLAN, $MMTK_MOVING and $MMTK_BUILD
286+
# if we use the BinaryBuilder version of mmtk-julia
287+
ifeq ($(USE_BINARYBUILDER_MMTK_JULIA),1)
288+
ifeq (${MMTK_PLAN},Immix)
289+
LIB_PATH_PLAN = immix
290+
else ifeq (${MMTK_PLAN},StickyImmix)
291+
LIB_PATH_PLAN = sticky
292+
endif
293+
294+
ifeq ($(MMTK_MOVING), 0)
295+
LIB_PATH_MOVING := non_moving
296+
else
297+
LIB_PATH_MOVING := moving
298+
endif
299+
300+
JL_PRIVATE_LIBS-0 += $(LIB_PATH_PLAN)/$(LIB_PATH_MOVING)/$(MMTK_BUILD)/libmmtk_julia
301+
else
285302
JL_PRIVATE_LIBS-0 += libmmtk_julia
286303
endif
304+
endif
287305

288306
# Note that we disable MSYS2's path munging here, as otherwise
289307
# it replaces our `:`-separated list as a `;`-separated one.

0 commit comments

Comments
 (0)