Skip to content

Commit 42ef684

Browse files
authored
Merge branch 'master' into submodules
2 parents 1e1a8ac + 0cf5a4d commit 42ef684

File tree

4 files changed

+141
-106
lines changed

4 files changed

+141
-106
lines changed

Compiler/src/abstractinterpretation.jl

Lines changed: 115 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3706,6 +3706,107 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
37063706
return typ
37073707
end
37083708

3709+
struct AbstractEvalBasicStatementResult
3710+
rt
3711+
exct
3712+
effects::Union{Nothing,Effects}
3713+
changes::Union{Nothing,StateUpdate}
3714+
refinements # ::Union{Nothing,SlotRefinement,Vector{Any}}
3715+
currsaw_latestworld::Bool
3716+
function AbstractEvalBasicStatementResult(rt, exct, effects::Union{Nothing,Effects},
3717+
changes::Union{Nothing,StateUpdate}, refinements, currsaw_latestworld::Bool)
3718+
@nospecialize rt exct refinements
3719+
return new(rt, exct, effects, changes, refinements, currsaw_latestworld)
3720+
end
3721+
end
3722+
3723+
function abstract_eval_basic_statement(interp::AbstractInterpreter, @nospecialize(stmt), sstate::StatementState, frame::InferenceState,
3724+
result::Union{Nothing,Future{RTEffects}}=nothing)
3725+
rt = nothing
3726+
exct = Bottom
3727+
changes = nothing
3728+
refinements = nothing
3729+
effects = nothing
3730+
currsaw_latestworld = sstate.saw_latestworld
3731+
if result !== nothing
3732+
@goto injectresult
3733+
end
3734+
if isa(stmt, NewvarNode)
3735+
changes = StateUpdate(stmt.slot, VarState(Bottom, true))
3736+
elseif isa(stmt, PhiNode)
3737+
add_curr_ssaflag!(frame, IR_FLAGS_REMOVABLE)
3738+
# Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
3739+
# the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
3740+
# over the first and last iterations. By tmerging in the current old_rt, we ensure that
3741+
# we will not lose an intermediate value.
3742+
rt = abstract_eval_phi(interp, stmt, sstate, frame)
3743+
old_rt = frame.ssavaluetypes[frame.currpc]
3744+
rt = old_rt === NOT_FOUND ? rt : tmerge(typeinf_lattice(interp), old_rt, rt)
3745+
else
3746+
lhs = nothing
3747+
if isexpr(stmt, :(=))
3748+
lhs = stmt.args[1]
3749+
stmt = stmt.args[2]
3750+
end
3751+
if !isa(stmt, Expr)
3752+
(; rt, exct, effects, refinements) = abstract_eval_special_value(interp, stmt, sstate, frame)
3753+
else
3754+
hd = stmt.head
3755+
if hd === :method
3756+
fname = stmt.args[1]
3757+
if isa(fname, SlotNumber)
3758+
changes = StateUpdate(fname, VarState(Any, false))
3759+
end
3760+
elseif (hd === :code_coverage_effect ||
3761+
# :boundscheck can be narrowed to Bool
3762+
(hd !== :boundscheck && is_meta_expr(stmt)))
3763+
rt = Nothing
3764+
elseif hd === :latestworld
3765+
currsaw_latestworld = true
3766+
rt = Nothing
3767+
else
3768+
result = abstract_eval_statement_expr(interp, stmt, sstate, frame)::Future{RTEffects}
3769+
if !isready(result) || !isempty(frame.tasks)
3770+
return result
3771+
3772+
@label injectresult
3773+
# reload local variables
3774+
lhs = nothing
3775+
if isexpr(stmt, :(=))
3776+
lhs = stmt.args[1]
3777+
stmt = stmt.args[2]
3778+
end
3779+
end
3780+
result = result[]
3781+
(; rt, exct, effects, refinements) = result
3782+
if effects.noub === NOUB_IF_NOINBOUNDS
3783+
if has_curr_ssaflag(frame, IR_FLAG_INBOUNDS)
3784+
effects = Effects(effects; noub=ALWAYS_FALSE)
3785+
elseif !propagate_inbounds(frame)
3786+
# The callee read our inbounds flag, but unless we propagate inbounds,
3787+
# we ourselves don't read our parent's inbounds.
3788+
effects = Effects(effects; noub=ALWAYS_TRUE)
3789+
end
3790+
end
3791+
@assert !isa(rt, TypeVar) "unhandled TypeVar"
3792+
rt = maybe_singleton_const(rt)
3793+
if !isempty(frame.pclimitations)
3794+
if rt isa Const || rt === Union{}
3795+
empty!(frame.pclimitations)
3796+
else
3797+
rt = LimitedAccuracy(rt, frame.pclimitations)
3798+
frame.pclimitations = IdSet{InferenceState}()
3799+
end
3800+
end
3801+
end
3802+
end
3803+
if lhs !== nothing && rt !== Bottom
3804+
changes = StateUpdate(lhs::SlotNumber, VarState(rt, false))
3805+
end
3806+
end
3807+
return AbstractEvalBasicStatementResult(rt, exct, effects, changes, refinements, currsaw_latestworld)
3808+
end
3809+
37093810
struct BestguessInfo{Interp<:AbstractInterpreter}
37103811
interp::Interp
37113812
bestguess
@@ -3986,14 +4087,16 @@ end
39864087

39874088
# make as much progress on `frame` as possible (without handling cycles)
39884089
struct CurrentState
3989-
result::Future
4090+
result::Future{RTEffects}
39904091
currstate::VarTable
39914092
currsaw_latestworld::Bool
39924093
bbstart::Int
39934094
bbend::Int
3994-
CurrentState(result::Future, currstate::VarTable, currsaw_latestworld::Bool, bbstart::Int, bbend::Int) = new(result, currstate, currsaw_latestworld, bbstart, bbend)
4095+
CurrentState(result::Future{RTEffects}, currstate::VarTable, currsaw_latestworld::Bool, bbstart::Int, bbend::Int) =
4096+
new(result, currstate, currsaw_latestworld, bbstart, bbend)
39954097
CurrentState() = new()
39964098
end
4099+
39974100
function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextresult::CurrentState)
39984101
@assert !is_inferred(frame)
39994102
W = frame.ip
@@ -4012,7 +4115,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
40124115
bbend = nextresult.bbend
40134116
currstate = nextresult.currstate
40144117
currsaw_latestworld = nextresult.currsaw_latestworld
4015-
@goto injectresult
4118+
stmt = frame.src.code[currpc]
4119+
result = abstract_eval_basic_statement(interp, stmt, StatementState(currstate, currsaw_latestworld), frame, nextresult.result)
4120+
@goto injected_result
40164121
end
40174122

40184123
if currbb != 1
@@ -4165,87 +4270,15 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
41654270
end
41664271
# Process non control-flow statements
41674272
@assert isempty(frame.tasks)
4168-
rt = nothing
4169-
exct = Bottom
4170-
changes = nothing
4171-
refinements = nothing
4172-
effects = nothing
4173-
if isa(stmt, NewvarNode)
4174-
changes = StateUpdate(stmt.slot, VarState(Bottom, true))
4175-
elseif isa(stmt, PhiNode)
4176-
add_curr_ssaflag!(frame, IR_FLAGS_REMOVABLE)
4177-
# Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
4178-
# the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
4179-
# over the first and last iterations. By tmerging in the current old_rt, we ensure that
4180-
# we will not lose an intermediate value.
4181-
rt = abstract_eval_phi(interp, stmt, StatementState(currstate, currsaw_latestworld), frame)
4182-
old_rt = frame.ssavaluetypes[currpc]
4183-
rt = old_rt === NOT_FOUND ? rt : tmerge(typeinf_lattice(interp), old_rt, rt)
4273+
sstate = StatementState(currstate, currsaw_latestworld)
4274+
result = abstract_eval_basic_statement(interp, stmt, sstate, frame)
4275+
if result isa Future{RTEffects}
4276+
return CurrentState(result, currstate, currsaw_latestworld, bbstart, bbend)
41844277
else
4185-
lhs = nothing
4186-
if isexpr(stmt, :(=))
4187-
lhs = stmt.args[1]
4188-
stmt = stmt.args[2]
4189-
end
4190-
if !isa(stmt, Expr)
4191-
(; rt, exct, effects, refinements) = abstract_eval_special_value(interp, stmt, StatementState(currstate, currsaw_latestworld), frame)
4192-
else
4193-
hd = stmt.head
4194-
if hd === :method
4195-
fname = stmt.args[1]
4196-
if isa(fname, SlotNumber)
4197-
changes = StateUpdate(fname, VarState(Any, false))
4198-
end
4199-
elseif (hd === :code_coverage_effect || (
4200-
hd !== :boundscheck && # :boundscheck can be narrowed to Bool
4201-
is_meta_expr(stmt)))
4202-
rt = Nothing
4203-
elseif hd === :latestworld
4204-
currsaw_latestworld = true
4205-
rt = Nothing
4206-
else
4207-
result = abstract_eval_statement_expr(interp, stmt, StatementState(currstate, currsaw_latestworld), frame)::Future
4208-
if !isready(result) || !isempty(frame.tasks)
4209-
return CurrentState(result, currstate, currsaw_latestworld, bbstart, bbend)
4210-
@label injectresult
4211-
# reload local variables
4212-
stmt = frame.src.code[currpc]
4213-
changes = nothing
4214-
lhs = nothing
4215-
if isexpr(stmt, :(=))
4216-
lhs = stmt.args[1]
4217-
stmt = stmt.args[2]
4218-
end
4219-
result = nextresult.result::Future{RTEffects}
4220-
end
4221-
result = result[]
4222-
(; rt, exct, effects, refinements) = result
4223-
if effects.noub === NOUB_IF_NOINBOUNDS
4224-
if has_curr_ssaflag(frame, IR_FLAG_INBOUNDS)
4225-
effects = Effects(effects; noub=ALWAYS_FALSE)
4226-
elseif !propagate_inbounds(frame)
4227-
# The callee read our inbounds flag, but unless we propagate inbounds,
4228-
# we ourselves don't read our parent's inbounds.
4229-
effects = Effects(effects; noub=ALWAYS_TRUE)
4230-
end
4231-
end
4232-
@assert !isa(rt, TypeVar) "unhandled TypeVar"
4233-
rt = maybe_singleton_const(rt)
4234-
if !isempty(frame.pclimitations)
4235-
if rt isa Const || rt === Union{}
4236-
empty!(frame.pclimitations)
4237-
else
4238-
rt = LimitedAccuracy(rt, frame.pclimitations)
4239-
frame.pclimitations = IdSet{InferenceState}()
4240-
end
4241-
end
4242-
end
4243-
end
4244-
effects === nothing || merge_override_effects!(interp, effects, frame)
4245-
if lhs !== nothing && rt !== Bottom
4246-
changes = StateUpdate(lhs::SlotNumber, VarState(rt, false))
4247-
end
4278+
@label injected_result
4279+
(; rt, exct, effects, changes, refinements, currsaw_latestworld) = result
42484280
end
4281+
effects === nothing || merge_override_effects!(interp, effects, frame)
42494282
if !has_curr_ssaflag(frame, IR_FLAG_NOTHROW)
42504283
if exct !== Union{}
42514284
update_exc_bestguess!(interp, exct, frame)

src/module.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,16 +1727,20 @@ JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr)
17271727
jl_binding_t *b = gr->binding;
17281728
if (!b)
17291729
b = jl_get_module_binding(gr->mod, gr->name, 1);
1730-
jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
17311730

1732-
if (jl_binding_kind(bpart) == PARTITION_KIND_GUARD) {
1733-
// Already guard
1731+
for (;;) {
1732+
jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_atomic_load_acquire(&jl_world_counter));
1733+
1734+
if (jl_binding_kind(bpart) == PARTITION_KIND_GUARD) {
1735+
// Already guard
1736+
return;
1737+
}
1738+
1739+
if (!jl_replace_binding(b, bpart, NULL, PARTITION_KIND_GUARD))
1740+
continue;
1741+
17341742
return;
17351743
}
1736-
1737-
for (;;)
1738-
if (jl_replace_binding(b, bpart, NULL, PARTITION_KIND_GUARD))
1739-
break;
17401744
}
17411745

17421746
JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var)

stdlib/Random/src/RNGs.jl

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -278,20 +278,7 @@ end
278278

279279
### seeding
280280

281-
#### random_seed() & hash_seed()
282-
283-
# random_seed tries to produce a random seed of type UInt128 from system entropy
284-
function random_seed()
285-
try
286-
# as MersenneTwister prints its seed when `show`ed, 128 bits is a good compromise for
287-
# almost surely always getting distinct seeds, while having them printed reasonably tersely
288-
return rand(RandomDevice(), UInt128)
289-
catch ex
290-
ex isa IOError || rethrow()
291-
@warn "Entropy pool not available to seed RNG; using ad-hoc entropy sources."
292-
return Libc.rand()
293-
end
294-
end
281+
#### hash_seed()
295282

296283
function hash_seed(seed::Integer)
297284
ctx = SHA.SHA2_256_CTX()
@@ -370,11 +357,13 @@ function initstate!(r::MersenneTwister, data::StridedVector, seed)
370357
return r
371358
end
372359

373-
# when a seed is not provided, we generate one via `RandomDevice()` in `random_seed()` rather
360+
# When a seed is not provided, we generate one via `RandomDevice()` rather
374361
# than calling directly `initstate!` with `rand(RandomDevice(), UInt32, whatever)` because the
375362
# seed is printed in `show(::MersenneTwister)`, so we need one; the cost of `hash_seed` is a
376-
# small overhead compared to `initstate!`, so this simple solution is fine
377-
seed!(r::MersenneTwister, ::Nothing) = seed!(r, random_seed())
363+
# small overhead compared to `initstate!`, so this simple solution is fine.
364+
# A random seed with 128 bits is a good compromise for almost surely always getting distinct
365+
# seeds, while having them printed reasonably tersely.
366+
seed!(r::MersenneTwister, ::Nothing) = seed!(r, rand(RandomDevice(), UInt128))
378367
seed!(r::MersenneTwister, seed) = initstate!(r, hash_seed(seed), seed)
379368

380369

test/rebinding.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,12 @@ end
383383

384384
# M3 connects all, so we should have a single partition
385385
@test access_and_count(:afterM3) == 1
386+
387+
# Test that delete_binding in an outdated world age works
388+
module BindingTestModule; end
389+
function create_and_delete_binding()
390+
Core.eval(BindingTestModule, :(const x = 1))
391+
Base.delete_binding(BindingTestModule, :x)
392+
end
393+
create_and_delete_binding()
394+
@test Base.binding_kind(BindingTestModule, :x) == Base.PARTITION_KIND_GUARD

0 commit comments

Comments
 (0)