Repository: JuliaLang/julia
File: Compiler/src/types.jl (Julia)

Code before:
- `bail_out_apply(::AbstractInterpreter, rt, ::InferenceState)`: bail out from
  `_apply_iterate` inference when return type `rt` grows up to `Any`

It also bails out from local statement/frame inference when any lattice element gets down to `Bottom`,
but `AbstractInterpreter` doesn't provide a specific interface for configuring it.
"""
function bail_out_toplevel_call end, function bail_out_call end, function bail_out_apply end

"""
    infer_compilation_signature(::AbstractInterpreter)::Bool

For some call sites (for example calls to varargs methods), the signature to be compiled
and executed at run time can differ from the argument types known at the call site.
This flag controls whether we should always infer the compilation signature in addition
to the call site signature.
"""
infer_compilation_signature(::AbstractInterpreter) = false
infer_compilation_signature(::NativeInterpreter) = true

typeinf_lattice(::AbstractInterpreter) = InferenceLattice(BaseInferenceLattice.instance)
ipo_lattice(::AbstractInterpreter) = InferenceLattice(IPOResultLattice.instance)
optimizer_lattice(::AbstractInterpreter) = SimpleInferenceLattice.instance

struct OverlayCodeCache{Cache, LocalCache}
    globalcache::Cache
    localcache::LocalCache
end

setindex!(cache::OverlayCodeCache, ci::CodeInstance, mi::MethodInstance) = (setindex!(cache.globalcache, ci, mi); cache)

haskey(cache::OverlayCodeCache, mi::MethodInstance) = get(cache, mi, nothing) !== nothing

# Fast path: use index when localcache is an InferenceCache
function get(cache::OverlayCodeCache{<:Any, InferenceCache}, mi::MethodInstance, default)
    localcache = cache.localcache
    indices = get_indices(localcache, mi)
    # Iterate in reverse to get the most recent matching entry
    for i in length(indices):-1:1
        cached_result = localcache.results[indices[i]]
        cached_result.tombstone && continue # ignore deleted entries (due to LimitedAccuracy)
        cached_result.overridden_by_const === nothing || continue
        isdefined(cached_result, :ci) || continue
        ci = cached_result.ci
        isdefined(ci, :inferred) || continue
        return cached_result
    end
    return get(cache.globalcache, mi, default)
end

# Slow path: linear scan for backward compatibility with Vector{InferenceResult}
function get(cache::OverlayCodeCache{<:Any, <:AbstractVector}, mi::MethodInstance, default)

Review comment (performance):
style nit: Don't make code unnecessarily slow and complicated for no reason
```suggestion
    localcache::InferenceCache
```

Code after:
  `_apply_iterate` inference when return type `rt` grows up to `Any`

It also bails out from local statement/frame inference when any lattice element gets down to `Bottom`,
but `AbstractInterpreter` doesn't provide a specific interface for configuring it.
"""
function bail_out_toplevel_call end, function bail_out_call end, function bail_out_apply end

"""
    infer_compilation_signature(::AbstractInterpreter)::Bool

For some call sites (for example calls to varargs methods), the signature to be compiled
and executed at run time can differ from the argument types known at the call site.
This flag controls whether we should always infer the compilation signature in addition
to the call site signature.
"""
infer_compilation_signature(::AbstractInterpreter) = false
infer_compilation_signature(::NativeInterpreter) = true

typeinf_lattice(::AbstractInterpreter) = InferenceLattice(BaseInferenceLattice.instance)
ipo_lattice(::AbstractInterpreter) = InferenceLattice(IPOResultLattice.instance)
optimizer_lattice(::AbstractInterpreter) = SimpleInferenceLattice.instance

struct OverlayCodeCache{Cache}
    globalcache::Cache
    localcache::InferenceCache
end

setindex!(cache::OverlayCodeCache, ci::CodeInstance, mi::MethodInstance) = (setindex!(cache.globalcache, ci, mi); cache)

haskey(cache::OverlayCodeCache, mi::MethodInstance) = get(cache, mi, nothing) !== nothing

function get(cache::OverlayCodeCache, mi::MethodInstance, default)
    localcache = cache.localcache
    indices = get_indices(localcache, mi)
    # Iterate in reverse to get the most recent matching entry
    for i in length(indices):-1:1
        cached_result = localcache.results[indices[i]]
        cached_result.tombstone && continue # ignore deleted entries (due to LimitedAccuracy)
        cached_result.overridden_by_const === nothing || continue
        isdefined(cached_result, :ci) || continue
        ci = cached_result.ci
        isdefined(ci, :inferred) || continue
        return cached_result
    end
    return get(cache.globalcache, mi, default)
end

function getindex(cache::OverlayCodeCache, mi::MethodInstance)
    r = get(cache, mi, nothing)
    r === nothing && throw(KeyError(mi))
    return r