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

Code before:
    if isa(third_arg_type, Const) && isa(third_arg_type.val, CodeInstance)
        return true
    end
    return false
end

# Transform invoke call with CodeInstance to :invoke expression
# Transforms: Expr(:call, invoke, f, ::CodeInstance, args...)
# Into: Expr(:invoke, ::CodeInstance, f, args...)
function transform_invoke_codeinstance!(ir::IRCode, idx::Int, stmt::Expr)
    # Extract the CodeInstance from stmt.args[3]
    ci_arg = stmt.args[3]

    # Resolve to actual CodeInstance if needed
    ci::CodeInstance = if isa(ci_arg, CodeInstance)
        ci_arg
    else
        ci_type = argextype(ci_arg, ir)
        if isa(ci_type, Const) && isa(ci_type.val, CodeInstance)
            ci_type.val
        else
            return false
        end
    end
    if @atomic(ci.invoke) == C_NULL
        @ccall jl_compile_codeinst(ci::Any)::Nothing
    end
    if @atomic(ci.invoke) == C_NULL
        # if invoke is still null after trying to compile the codeinstance, we just fall back
        # to the interpreter, which will handle errors, or falling back to the methodinstance.
        return false
    end
    if ir.valid_worlds.min_world < @atomic(ci.min_world) ||  @atomic(ci.max_world) < ir.valid_worlds.max_world
        # If the code instance has a world range that's inappropriate for our IR, fall
        # back to the interpreter which will raise an appropriate error
        return false
    end
    # Rebuild as: Expr(:invoke, CodeInstance, f, args...)
    stmt.head = :invoke
    stmt.args = Any[ci, stmt.args[2], stmt.args[4:end]...]
    return true
end

function handle_invoke_call!(todo::Vector{Pair{Int,Any}},
    ir::IRCode, idx::Int, stmt::Expr, @nospecialize(info), flag::UInt32,
    sig::Signature, state::InliningState)

    # Check for invoke with CodeInstance pattern and transform it
    # This allows invoke calls with CodeInstance to be resolved at compile time
    # Pattern: Expr(:call, invoke, f, ::CodeInstance, args...)
    # Transformed into: Expr(:invoke, ::CodeInstance, f, args...)

Review comment (bug):
This can potentially cause stack overflow or deadlock and is not safe here. Observing the value of invoke (other than for const flag) is invalid in inference therefore 

Code after:
    if isa(result, ConcreteResult)
        item = concrete_result_item(result, info, state)
    elseif isa(result, SemiConcreteResult)
        item = semiconcrete_result_item(result, info, flag, state)
    else
        argtypes = invoke_rewrite(sig.argtypes)
        if isa(result, InferenceResult)
            mi = result.linfo
            validate_sparams(mi.sparam_vals) || return nothing
            if Union{} !== argtypes_to_type(argtypes) <: mi.def.sig
                item = resolve_todo(mi, result, info, flag, state)
                handle_single_case!(todo, ir, idx, stmt, item, true)
                return nothing
            end
        end
        item = analyze_method!(result, match, argtypes, info, flag, state; allow_typevars=false)
    end
    handle_single_case!(todo, ir, idx, stmt, item, true)
    return nothing
end

function invoke_signature(argtypes::Vector{Any})
    ft, argtyps = widenconst(argtypes[2]), instanceof_tfunc(widenconst(argtypes[3]), false)[1]
    return rewrap_unionall(Tuple{ft, unwrap_unionall(argtyps).parameters...}, argtyps)
end

function narrow_opaque_closure!(ir::IRCode, stmt::Expr, @nospecialize(info::CallInfo), state::InliningState)
    if isa(info, OpaqueClosureCreateInfo)
        lbt = argextype(stmt.args[2], ir)
        lb, exact = instanceof_tfunc(lbt)
        exact || return
        ubt = argextype(stmt.args[3], ir)
        ub, exact = instanceof_tfunc(ubt)
        exact || return
        # Narrow opaque closure type
        𝕃ₒ = optimizer_lattice(state.interp)
        newT = widenconst(tmeet(𝕃ₒ, tmerge(𝕃ₒ, lb, info.unspec.rt), ub))
        if newT != ub
            # N.B.: Narrowing the ub requires a backedge on the mi whose type
            # information we're using, since a change in that function may
            # invalidate ub result.
            stmt.args[3] = newT
        end
    end
end

# As a matter of convenience, this pass also computes effect-freenes.
# For primitives, we do that right here. For proper calls, we will
# discover this when we consult the caches.
add_inst_flag!(inst::Instruction, ir::IRCode, state::InliningState) =
    add_inst_flag!(inst, ir, optimizer_lattice(state.interp))