Repository: JuliaLang/julia
File: src/gf.c (C)

Code before:
                jl_method_instance_t *mi = entry->func.linfo;
                jl_method_t *meth = mi->def.method;
                if (!jl_is_unionall(meth->sig) && ((jl_datatype_t*)unw)->isdispatchtuple) {
                    env.match.env = jl_emptysvec;
                    env.match.ti = unw;
                }
                else {
                    // this just calls jl_subtype_env (since we know that `type <: meth->sig` by transitivity)
                    env.match.ti = jl_type_intersection_env((jl_value_t*)type, (jl_value_t*)meth->sig, &env.match.env);
                }
                env.matc = make_method_match((jl_tupletype_t*)env.match.ti,
                    env.match.env, meth, FULLY_COVERS);
                env.t = (jl_value_t*)jl_alloc_vec_any(1);
                jl_array_ptr_set(env.t, 0, env.matc);
                size_t min_world = jl_atomic_load_relaxed(&entry->min_world);
                size_t max_world = jl_atomic_load_relaxed(&entry->max_world);
                if (*min_valid < min_world)
                    *min_valid = min_world;
                if (*max_valid > max_world)
                    *max_valid = max_world;
                JL_GC_POP();
                return env.t;
            }
        }

        // if neither cache worked (or was eligible / profitable) visit all matching methods in the MethodTable
        // via the usual typemap visitor, recording any matches in closure->t.
        if (!ml_mtable_visitor(mt, &env.match)) {
            JL_GC_POP();
            // if we return early, lim was proven to be exceeded during the search
            // set only the min/max valid collected from matching
            *min_valid = env.match.min_valid;
            *max_valid = env.match.max_valid;
            return jl_nothing;
        }
    }
    else {
        // if mt is not NULL, then we were unable to narrow down the call to a single
        // MethodTable (e.g. type is `Tuple{Union{typeof(+), typeof(-)}, Int, Int}`)
        //
        // this case is quite rare, so fall back to scanning all method tables
        // (with the same ml_mtable_visitor as usual)
        if (!jl_foreach_reachable_mtable(ml_mtable_visitor, &env.match)) {
            JL_GC_POP();
            // if we return early, set only the min/max valid collected from matching
            *min_valid = env.match.min_valid;
            *max_valid = env.match.max_valid;
            return jl_nothing;
        }
    }
    // if we return early, set only the min/max valid collected from matching

Review comment (performance):
```suggestion
        // if neither cache worked (or was deemed unprofitable to check) visit all matching methods in the MethodTable
```

Code after:
    // Deprecated: Use jl_gf_invoke_lookup_worlds for future development
    size_t min_valid = 0;
    size_t max_valid = ~(size_t)0;
    if (mt == jl_nothing)
        mt = (jl_value_t*)jl_method_table;
    jl_method_match_t *matc = _gf_invoke_lookup(types, (jl_methtable_t*)mt, world, 1, &min_valid, &max_valid);
    if (matc == NULL)
        return jl_nothing;
    return (jl_value_t*)matc->method;
}


JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup_worlds(jl_value_t *types, jl_value_t *mt, size_t world, size_t *min_world, size_t *max_world)
{
    if (mt == jl_nothing)
        mt = (jl_value_t*)jl_method_table;
    jl_method_match_t *matc = _gf_invoke_lookup(types, (jl_methtable_t*)mt, world, 1, min_world, max_world);
    if (matc == NULL)
        return jl_nothing;
    return (jl_value_t*)matc;
}

// invoke()
// this does method dispatch with a set of types to match other than the
// types of the actual arguments. this means it sometimes does NOT call the
// most specific method for the argument types, so we need different logic.
// first we use the given types to look up a definition, then we perform
// caching and specialization within just that definition.
// every definition has its own private method table for this purpose.
//
// NOTE: assumes argument type is a subtype of the lookup type.
jl_value_t *jl_gf_invoke(jl_value_t *types0, jl_value_t *gf, jl_value_t **args, size_t nargs)
{
    size_t world = jl_current_task->world_age;
    jl_value_t *types = NULL;
    JL_GC_PUSH1(&types);
    types = jl_argtype_with_function((jl_value_t*)gf, types0);
    jl_method_t *method = (jl_method_t*)jl_gf_invoke_lookup(types, jl_nothing, world);
    JL_GC_PROMISE_ROOTED(method);

    if ((jl_value_t*)method == jl_nothing) {
        jl_method_error_bare(gf, types0, world);
        // unreachable
    }

    // now we have found the matching definition.
    // next look for or create a specialization of this definition.
    JL_GC_POP();
    return jl_gf_invoke_by_method(method, gf, args, nargs);
}