Skip to content

Commit 0bc1c59

Browse files
authored
Merge branch 'master' into prevent_stack_overflow_in_type_promotion
2 parents fac1ce7 + 2dd4cdf commit 0bc1c59

Some content is hidden

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

65 files changed

+1161
-562
lines changed

Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,74 @@
11
module CompilerDevTools
22

33
using Compiler
4+
using Compiler: argextype, widenconst
45
using Core.IR
6+
using Base: isexpr
7+
8+
mutable struct SplitCacheOwner end
59

6-
struct SplitCacheOwner; end
710
struct SplitCacheInterp <: Compiler.AbstractInterpreter
811
world::UInt
12+
owner::SplitCacheOwner
913
inf_params::Compiler.InferenceParams
1014
opt_params::Compiler.OptimizationParams
1115
inf_cache::Vector{Compiler.InferenceResult}
1216
codegen_cache::IdDict{CodeInstance,CodeInfo}
1317
function SplitCacheInterp(;
1418
world::UInt = Base.get_world_counter(),
19+
owner::SplitCacheOwner = SplitCacheOwner(),
1520
inf_params::Compiler.InferenceParams = Compiler.InferenceParams(),
1621
opt_params::Compiler.OptimizationParams = Compiler.OptimizationParams(),
1722
inf_cache::Vector{Compiler.InferenceResult} = Compiler.InferenceResult[])
18-
new(world, inf_params, opt_params, inf_cache, IdDict{CodeInstance,CodeInfo}())
23+
new(world, owner, inf_params, opt_params, inf_cache, IdDict{CodeInstance,CodeInfo}())
1924
end
2025
end
2126

2227
Compiler.InferenceParams(interp::SplitCacheInterp) = interp.inf_params
2328
Compiler.OptimizationParams(interp::SplitCacheInterp) = interp.opt_params
2429
Compiler.get_inference_world(interp::SplitCacheInterp) = interp.world
2530
Compiler.get_inference_cache(interp::SplitCacheInterp) = interp.inf_cache
26-
Compiler.cache_owner(::SplitCacheInterp) = SplitCacheOwner()
31+
Compiler.cache_owner(interp::SplitCacheInterp) = interp.owner
2732
Compiler.codegen_cache(interp::SplitCacheInterp) = interp.codegen_cache
2833

2934
import Core.OptimizedGenerics.CompilerPlugins: typeinf, typeinf_edge
30-
@eval @noinline typeinf(::SplitCacheOwner, mi::MethodInstance, source_mode::UInt8) =
31-
Base.invoke_in_world(which(typeinf, Tuple{SplitCacheOwner, MethodInstance, UInt8}).primary_world, Compiler.typeinf_ext_toplevel, SplitCacheInterp(; world=Base.tls_world_age()), mi, source_mode)
35+
@eval @noinline typeinf(owner::SplitCacheOwner, mi::MethodInstance, source_mode::UInt8) =
36+
Base.invoke_in_world(which(typeinf, Tuple{SplitCacheOwner, MethodInstance, UInt8}).primary_world, Compiler.typeinf_ext_toplevel, SplitCacheInterp(; world=Base.tls_world_age(), owner), mi, source_mode)
3237

33-
@eval @noinline function typeinf_edge(::SplitCacheOwner, mi::MethodInstance, parent_frame::Compiler.InferenceState, world::UInt, source_mode::UInt8)
38+
@eval @noinline function typeinf_edge(owner::SplitCacheOwner, mi::MethodInstance, parent_frame::Compiler.InferenceState, world::UInt, source_mode::UInt8)
3439
# TODO: This isn't quite right, we're just sketching things for now
35-
interp = SplitCacheInterp(; world)
40+
interp = SplitCacheInterp(; world, owner)
3641
Compiler.typeinf_edge(interp, mi.def, mi.specTypes, Core.svec(), parent_frame, false, false)
3742
end
3843

39-
function with_new_compiler(f, args...)
40-
mi = @ccall jl_method_lookup(Any[f, args...]::Ptr{Any}, (1+length(args))::Csize_t, Base.tls_world_age()::Csize_t)::Ref{Core.MethodInstance}
41-
world = Base.tls_world_age()
44+
function lookup_method_instance(f, args...)
45+
@ccall jl_method_lookup(Any[f, args...]::Ptr{Any}, (1+length(args))::Csize_t, Base.tls_world_age()::Csize_t)::Ref{Core.MethodInstance}
46+
end
47+
48+
function Compiler.optimize(interp::SplitCacheInterp, opt::Compiler.OptimizationState, caller::Compiler.InferenceResult)
49+
@invoke Compiler.optimize(interp::Compiler.AbstractInterpreter, opt::Compiler.OptimizationState, caller::Compiler.InferenceResult)
50+
ir = opt.ir::Compiler.IRCode
51+
override = GlobalRef(@__MODULE__(), :with_new_compiler)
52+
for inst in ir.stmts
53+
stmt = inst[:stmt]
54+
isexpr(stmt, :call) || continue
55+
f = stmt.args[1]
56+
f === override && continue
57+
if isa(f, GlobalRef)
58+
T = widenconst(argextype(f, ir))
59+
T <: Core.Builtin && continue
60+
end
61+
insert!(stmt.args, 1, override)
62+
insert!(stmt.args, 3, interp.owner)
63+
end
64+
end
65+
66+
with_new_compiler(f, args...; owner::SplitCacheOwner = SplitCacheOwner()) = with_new_compiler(f, owner, args...)
67+
68+
function with_new_compiler(f, owner::SplitCacheOwner, args...)
69+
mi = lookup_method_instance(f, args...)
4270
new_compiler_ci = Core.OptimizedGenerics.CompilerPlugins.typeinf(
43-
SplitCacheOwner(), mi, Compiler.SOURCE_MODE_ABI
71+
owner, mi, Compiler.SOURCE_MODE_ABI
4472
)
4573
invoke(f, new_compiler_ci, args...)
4674
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Test
2+
using Compiler: code_cache
3+
using Base: inferencebarrier
4+
using CompilerDevTools
5+
using CompilerDevTools: lookup_method_instance, SplitCacheInterp
6+
7+
@testset "CompilerDevTools" begin
8+
do_work(x, y) = x + y
9+
f1() = do_work(inferencebarrier(1), inferencebarrier(2))
10+
interp = SplitCacheInterp()
11+
cache = code_cache(interp)
12+
mi = lookup_method_instance(f1)
13+
@test !haskey(cache, mi)
14+
@test with_new_compiler(f1, interp.owner) === 3
15+
@test haskey(cache, mi)
16+
# Here `do_work` is compiled at runtime, and so must have
17+
# required extra work to be cached under the same cache owner.
18+
mi = lookup_method_instance(do_work, 1, 2)
19+
@test haskey(cache, mi)
20+
end;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
using Pkg
2+
3+
Pkg.activate(dirname(@__DIR__)) do
4+
Pkg.instantiate()
5+
include("runtests.jl")
6+
end

Compiler/src/Compiler.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstanc
5050
using Base
5151
using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospecializeinfer,
5252
BINDING_KIND_GLOBAL, BINDING_KIND_UNDEF_CONST, BINDING_KIND_BACKDATED_CONST, BINDING_KIND_DECLARED,
53+
BINDING_FLAG_DEPWARN,
5354
Base, BitVector, Bottom, Callable, DataTypeFieldDesc,
5455
EffectsOverride, Filter, Generator, IteratorSize, JLOptions, NUM_EFFECTS_OVERRIDES,
5556
OneTo, Ordering, RefValue, SizeUnknown, _NAMEDTUPLE_NAME,
@@ -82,6 +83,10 @@ const modifyproperty! = Core.modifyfield!
8283
const replaceproperty! = Core.replacefield!
8384
const _DOCS_ALIASING_WARNING = ""
8485

86+
function _getundef(p::PartialStruct)
87+
Base.getproperty(p, :undef)
88+
end
89+
8590
ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Compiler, false)
8691

8792
eval(x) = Core.eval(Compiler, x)

Compiler/src/abstractinterpretation.jl

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -286,19 +286,12 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(fun
286286
state.rettype = Any
287287
end
288288
# if from_interprocedural added any pclimitations to the set inherited from the arguments,
289-
# some of those may be part of our cycles, so those can be deleted now
290-
# TODO: and those might need to be deleted later too if the cycle grows to include them?
291289
if isa(sv, InferenceState)
292290
# TODO (#48913) implement a proper recursion handling for irinterp:
293-
# This works just because currently the `:terminate` condition guarantees that
294-
# irinterp doesn't fail into unresolved cycles, but it's not a good solution.
291+
# This works most of the time just because currently the `:terminate` condition often guarantees that
292+
# irinterp doesn't fail into unresolved cycles, but it is not a good (or working) solution.
295293
# We should revisit this once we have a better story for handling cycles in irinterp.
296-
if !isempty(sv.pclimitations) # remove self, if present
297-
delete!(sv.pclimitations, sv)
298-
for caller in callers_in_cycle(sv)
299-
delete!(sv.pclimitations, caller)
300-
end
301-
end
294+
delete!(sv.pclimitations, sv) # remove self, if present
302295
end
303296
else
304297
# there is unanalyzed candidate, widen type and effects to the top
@@ -775,7 +768,7 @@ function edge_matches_sv(interp::AbstractInterpreter, frame::AbsIntState,
775768
# check in the cycle list first
776769
# all items in here are considered mutual parents of all others
777770
if !any(p::AbsIntState->matches_sv(p, sv), callers_in_cycle(frame))
778-
let parent = frame_parent(frame)
771+
let parent = cycle_parent(frame)
779772
parent === nothing && return false
780773
(is_cached(parent) || frame_parent(parent) !== nothing) || return false
781774
matches_sv(parent, sv) || return false
@@ -1379,6 +1372,7 @@ function const_prop_call(interp::AbstractInterpreter,
13791372
inf_result.result = concrete_eval_result.rt
13801373
inf_result.ipo_effects = concrete_eval_result.effects
13811374
end
1375+
typ = inf_result.result
13821376
return const_prop_result(inf_result)
13831377
end
13841378

@@ -2381,7 +2375,7 @@ function abstract_throw_methoderror(interp::AbstractInterpreter, argtypes::Vecto
23812375
return Future(CallMeta(Union{}, exct, EFFECTS_THROWS, NoCallInfo()))
23822376
end
23832377

2384-
const generic_getglobal_effects = Effects(EFFECTS_THROWS, consistent=ALWAYS_FALSE, inaccessiblememonly=ALWAYS_FALSE)
2378+
const generic_getglobal_effects = Effects(EFFECTS_THROWS, effect_free=ALWAYS_FALSE, consistent=ALWAYS_FALSE, inaccessiblememonly=ALWAYS_FALSE) #= effect_free for depwarn =#
23852379
const generic_getglobal_exct = Union{ArgumentError, TypeError, ConcurrencyViolationError, UndefVarError}
23862380
function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, @nospecialize(M), @nospecialize(s))
23872381
= partialorder(typeinf_lattice(interp))
@@ -3509,32 +3503,36 @@ end
35093503

35103504
function abstract_eval_partition_load(interp::AbstractInterpreter, partition::Core.BindingPartition)
35113505
kind = binding_kind(partition)
3506+
isdepwarn = (partition.kind & BINDING_FLAG_DEPWARN) != 0
3507+
local_getglobal_effects = Effects(generic_getglobal_effects, effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE)
35123508
if is_some_guard(kind) || kind == BINDING_KIND_UNDEF_CONST
35133509
if InferenceParams(interp).assume_bindings_static
35143510
return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
35153511
else
35163512
# We do not currently assume an invalidation for guard -> defined transitions
35173513
# return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
3518-
return RTEffects(Any, UndefVarError, generic_getglobal_effects)
3514+
return RTEffects(Any, UndefVarError, local_getglobal_effects)
35193515
end
35203516
end
35213517

35223518
if is_defined_const_binding(kind)
35233519
if kind == BINDING_KIND_BACKDATED_CONST
35243520
# Infer this as guard. We do not want a later const definition to retroactively improve
35253521
# inference results in an earlier world.
3526-
return RTEffects(Any, UndefVarError, generic_getglobal_effects)
3522+
return RTEffects(Any, UndefVarError, local_getglobal_effects)
35273523
end
35283524
rt = Const(partition_restriction(partition))
3529-
return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL, inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE))
3525+
return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL,
3526+
inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE,
3527+
effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE))
35303528
end
35313529

35323530
if kind == BINDING_KIND_DECLARED
35333531
rt = Any
35343532
else
35353533
rt = partition_restriction(partition)
35363534
end
3537-
return RTEffects(rt, UndefVarError, generic_getglobal_effects)
3535+
return RTEffects(rt, UndefVarError, local_getglobal_effects)
35383536
end
35393537

35403538
function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, saw_latestworld::Bool, sv::AbsIntState)

Compiler/src/inferenceresult.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ function cache_lookup(𝕃::AbstractLattice, mi::MethodInstance, given_argtypes:
183183
method = mi.def::Method
184184
nargtypes = length(given_argtypes)
185185
for cached_result in cache
186-
cached_result.linfo === mi || @goto next_cache
186+
cached_result.tombstone && continue # ignore deleted entries (due to LimitedAccuracy)
187+
cached_result.linfo === mi || continue
187188
cache_argtypes = cached_result.argtypes
188189
@assert length(cache_argtypes) == nargtypes "invalid `cache_argtypes` for `mi`"
189190
cache_overridden_by_const = cached_result.overridden_by_const::BitVector

Compiler/src/inferencestate.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ mutable struct InferenceState
292292

293293
# IPO tracking of in-process work, shared with all frames given AbstractInterpreter
294294
callstack #::Vector{AbsIntState}
295-
parentid::Int # index into callstack of the parent frame that originally added this frame (call frame_parent to extract the current parent of the SCC)
295+
parentid::Int # index into callstack of the parent frame that originally added this frame (call cycle_parent to extract the current parent of the SCC)
296296
frameid::Int # index into callstack at which this object is found (or zero, if this is not a cached frame and has no parent)
297297
cycleid::Int # index into the callstack of the topmost frame in the cycle (all frames in the same cycle share the same cycleid)
298298

@@ -908,14 +908,17 @@ function frame_module(sv::AbsIntState)
908908
return def.module
909909
end
910910

911-
function frame_parent(sv::InferenceState)
911+
frame_parent(sv::AbsIntState) = sv.parentid == 0 ? nothing : (sv.callstack::Vector{AbsIntState})[sv.parentid]
912+
913+
function cycle_parent(sv::InferenceState)
912914
sv.parentid == 0 && return nothing
913915
callstack = sv.callstack::Vector{AbsIntState}
914916
sv = callstack[sv.cycleid]::InferenceState
915917
sv.parentid == 0 && return nothing
916918
return callstack[sv.parentid]
917919
end
918-
frame_parent(sv::IRInterpretationState) = sv.parentid == 0 ? nothing : (sv.callstack::Vector{AbsIntState})[sv.parentid]
920+
cycle_parent(sv::IRInterpretationState) = frame_parent(sv)
921+
919922

920923
# add the orphan child to the parent and the parent to the child
921924
function assign_parentchild!(child::InferenceState, parent::AbsIntState)

Compiler/src/ssair/irinterp.jl

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

33
function collect_limitations!(@nospecialize(typ), ::IRInterpretationState)
4-
@assert !isa(typ, LimitedAccuracy) "irinterp is unable to handle heavy recursion"
4+
@assert !isa(typ, LimitedAccuracy) "irinterp is unable to handle heavy recursion correctly"
55
return typ
66
end
77

@@ -212,6 +212,7 @@ function reprocess_instruction!(interp::AbstractInterpreter, inst::Instruction,
212212
else
213213
rt = argextype(stmt, irsv.ir)
214214
end
215+
@assert !(rt isa LimitedAccuracy)
215216
if rt !== nothing
216217
if has_flag(inst, IR_FLAG_UNUSED)
217218
# Don't bother checking the type if we know it's unused

0 commit comments

Comments
 (0)