Skip to content

Commit 39caf28

Browse files
Kenomaleadt
andauthored
Add support for external method tables (#39697)
This PR implements a way to keep tables of methods that are not part of the internal method table, but still participate in the special support we have for keeping tables of methods, in particular unification through precompilation and efficient lookup. The intended design use case is to allow for method overlay tables for various non-CPU backends (e.g. GPU and TPU). These backends would like to modify basic function like `sin` to perform better on the device in question (or in the case of TPU to define them over non-LLVM intrinsics). To date, the best available mechanism of achieving this result was to use a Cassette-like pass rewriting every method and injecting an overlay if necessary. However, this approach is somewhat unsatisfying for two reasons: 1. It requires rewriting every function, which has non-trivial performance cost. 2. It is (currently) expensive because of the repeated calls to generated functions. 3. It confuses inference, because suddenly everything is one method. We have hooks to work around this, but support is incomplete. It is also not clear that Cassette it is the best conceptual model, because these methods *are* methods of the same generic function, they just happen to only be applicable for a particular backend. It is worth noting that this PR only gives the ability to keep these tables of methods. It assigns no particular meaning to them and the runtime (and regular inference) do not look at them. They are designed as an implementation detail for external compilers and similar tools. This feature does not replace Cassette for the method-interception use case in the absence of such a compiler, though it could in the future form part of a solution (I'm hoping the AD work will in due course lead to abstractions that would enable a "faster Cassette" which may use part of these fetaures). As such, I'm not sure we'll ever move this out of Experimental, but until such a time that we have a better solution, I think this'll be a useful feature for the GPU stack. With all those disclaimers out of the way, here is a description of the various parts of the current design that deserve discussion: # Demo ```julia julia> using Base.Experimental: @overlay, @MethodTable julia> @MethodTable(mt) # 0 methods: julia> mt # 0 methods: julia> @overlay mt function sin(x::Float64) 1 end julia> @overlay mt function cos(x::Float64) 1 end julia> mt # 2 methods: [1] cos(x::Float64) in Main at REPL[5]:1 [2] sin(x::Float64) in Main at REPL[4]:1 julia> Base._methods_by_ftype(Tuple{typeof(sin), Float64}, mt, 1, typemax(UInt)) 1-element Vector{Any}: Core.MethodMatch(Tuple{typeof(sin), Float64}, svec(), sin(x::Float64) in Main at REPL[4]:1, true) julia> Base._methods_by_ftype(Tuple{typeof(sin), Float64}, 1, typemax(UInt)) 1-element Vector{Any}: Core.MethodMatch(Tuple{typeof(sin), Float64}, svec(Float64), sin(x::T) where T<:Union{Float32, Float64} in Base.Math at special/trig.jl:29, true) ``` # The `@overlay` macro The macro replaces the function name by an `Expr(:overlay, mt, name)`, which then gets piped through to Method def. One particular design aspect here is that I've stopped letting the 4-argument :method Expr introduce new generic functions, reserving this functionality entirely to the 2-argument :method Expr. We already started going this way when we began omitting method names from the 4-argument version. This PR re-uses that name field of the 4-argument version to specify a method table instead. # Identity of methods I think one of the biggest questions of this design is what happens to the identity of methods. Until OpaqueClosure, all methods were uniquely identified by their signatures, with the applicable method table computed from the first argument of the signature. This is important so that incremental compilation can properly merge method tables coming from different .ji files. For these methods, that is of course not the correct method table to use for these methods, so methods that are not part of the internal method table will instead have a backreference to the applicable method table. # Identity of method tables Method tables are identified by the name of their binding in the containing module. To ensure consistency of this mapping, these MethodTables may only be constructed using the `@MethodTable(name)` macro, which simultaneously establishes a const binding in the declaring module. Co-authored-by: Tim Besard <tim@juliacomputing.com>
1 parent b054be5 commit 39caf28

File tree

16 files changed

+319
-97
lines changed

16 files changed

+319
-97
lines changed

base/compiler/methodtable.jl

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ struct InternalMethodTable <: MethodTableView
2828
world::UInt
2929
end
3030

31+
"""
32+
struct OverlayMethodTable <: MethodTableView
33+
34+
Overlays the internal method table such that specific queries can be redirected to an
35+
external table, e.g., to override existing method.
36+
"""
37+
struct OverlayMethodTable <: MethodTableView
38+
world::UInt
39+
mt::Core.MethodTable
40+
end
41+
3142
"""
3243
struct CachedMethodTable <: MethodTableView
3344
@@ -54,7 +65,26 @@ function findall(@nospecialize(sig::Type{<:Tuple}), table::InternalMethodTable;
5465
_min_val = RefValue{UInt}(typemin(UInt))
5566
_max_val = RefValue{UInt}(typemax(UInt))
5667
_ambig = RefValue{Int32}(0)
57-
ms = _methods_by_ftype(sig, limit, table.world, false, _min_val, _max_val, _ambig)
68+
ms = _methods_by_ftype(sig, nothing, limit, table.world, false, _min_val, _max_val, _ambig)
69+
if ms === false
70+
return missing
71+
end
72+
return MethodLookupResult(ms::Vector{Any}, WorldRange(_min_val[], _max_val[]), _ambig[] != 0)
73+
end
74+
75+
function findall(@nospecialize(sig::Type{<:Tuple}), table::OverlayMethodTable; limit::Int=typemax(Int))
76+
_min_val = RefValue{UInt}(typemin(UInt))
77+
_max_val = RefValue{UInt}(typemax(UInt))
78+
_ambig = RefValue{Int32}(0)
79+
ms = _methods_by_ftype(sig, table.mt, limit, table.world, false, _min_val, _max_val, _ambig)
80+
if ms === false
81+
return missing
82+
elseif isempty(ms)
83+
# fall back to the internal method table
84+
_min_val[] = typemin(UInt)
85+
_max_val[] = typemax(UInt)
86+
ms = _methods_by_ftype(sig, nothing, limit, table.world, false, _min_val, _max_val, _ambig)
87+
end
5888
if ms === false
5989
return missing
6090
end

base/experimental.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
module Experimental
1111

1212
using Base: Threads, sync_varname
13+
using Base.Meta
1314

1415
"""
1516
Const(A::Array)
@@ -256,4 +257,36 @@ end
256257
# OpaqueClosure
257258
include("opaque_closure.jl")
258259

260+
"""
261+
Experimental.@overlay mt [function def]
262+
263+
Define a method and add it to the method table `mt` instead of to the global method table.
264+
This can be used to implement a method override mechanism. Regular compilation will not
265+
consider these methods, and you should customize the compilation flow to look in these
266+
method tables (e.g., using [`Core.Compiler.OverlayMethodTable`](@ref)).
267+
268+
"""
269+
macro overlay(mt, def)
270+
def = macroexpand(__module__, def) # to expand @inline, @generated, etc
271+
if !isexpr(def, [:function, :(=)]) || !isexpr(def.args[1], :call)
272+
error("@overlay requires a function Expr")
273+
end
274+
def.args[1].args[1] = Expr(:overlay, mt, def.args[1].args[1])
275+
esc(def)
276+
end
277+
278+
"""
279+
Experimental.@MethodTable(name)
280+
281+
Create a new MethodTable in the current module, bound to `name`. This method table can be
282+
used with the [`Experimental.@overlay`](@ref) macro to define methods for a function without
283+
adding them to the global method table.
284+
"""
285+
macro MethodTable(name)
286+
isa(name, Symbol) || error("name must be a symbol")
287+
esc(quote
288+
const $name = ccall(:jl_new_method_table, Any, (Any, Any), $(quot(name)), $(__module__))
289+
end)
290+
end
291+
259292
end

base/reflection.jl

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -895,13 +895,16 @@ function _methods(@nospecialize(f), @nospecialize(t), lim::Int, world::UInt)
895895
end
896896

897897
function _methods_by_ftype(@nospecialize(t), lim::Int, world::UInt)
898-
return _methods_by_ftype(t, lim, world, false, RefValue{UInt}(typemin(UInt)), RefValue{UInt}(typemax(UInt)), Ptr{Int32}(C_NULL))
898+
return _methods_by_ftype(t, nothing, lim, world)
899899
end
900-
function _methods_by_ftype(@nospecialize(t), lim::Int, world::UInt, ambig::Bool, min::Array{UInt,1}, max::Array{UInt,1}, has_ambig::Array{Int32,1})
901-
return ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}, Ptr{Int32}), t, lim, ambig, world, min, max, has_ambig)::Union{Array{Any,1}, Bool}
900+
function _methods_by_ftype(@nospecialize(t), mt::Union{Core.MethodTable, Nothing}, lim::Int, world::UInt)
901+
return _methods_by_ftype(t, mt, lim, world, false, RefValue{UInt}(typemin(UInt)), RefValue{UInt}(typemax(UInt)), Ptr{Int32}(C_NULL))
902902
end
903-
function _methods_by_ftype(@nospecialize(t), lim::Int, world::UInt, ambig::Bool, min::Ref{UInt}, max::Ref{UInt}, has_ambig::Ref{Int32})
904-
return ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}, Ptr{Int32}), t, lim, ambig, world, min, max, has_ambig)::Union{Array{Any,1}, Bool}
903+
function _methods_by_ftype(@nospecialize(t), mt::Union{Core.MethodTable, Nothing}, lim::Int, world::UInt, ambig::Bool, min::Array{UInt,1}, max::Array{UInt,1}, has_ambig::Array{Int32,1})
904+
return ccall(:jl_matching_methods, Any, (Any, Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}, Ptr{Int32}), t, mt, lim, ambig, world, min, max, has_ambig)::Union{Array{Any,1}, Bool}
905+
end
906+
function _methods_by_ftype(@nospecialize(t), mt::Union{Core.MethodTable, Nothing}, lim::Int, world::UInt, ambig::Bool, min::Ref{UInt}, max::Ref{UInt}, has_ambig::Ref{Int32})
907+
return ccall(:jl_matching_methods, Any, (Any, Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}, Ptr{Int32}), t, mt, lim, ambig, world, min, max, has_ambig)::Union{Array{Any,1}, Bool}
905908
end
906909

907910
function _method_by_ftype(args...)
@@ -971,7 +974,7 @@ function methods_including_ambiguous(@nospecialize(f), @nospecialize(t))
971974
world = typemax(UInt)
972975
min = RefValue{UInt}(typemin(UInt))
973976
max = RefValue{UInt}(typemax(UInt))
974-
ms = _methods_by_ftype(tt, -1, world, true, min, max, Ptr{Int32}(C_NULL))
977+
ms = _methods_by_ftype(tt, nothing, -1, world, true, min, max, Ptr{Int32}(C_NULL))
975978
isa(ms, Bool) && return ms
976979
return MethodList(Method[(m::Core.MethodMatch).method for m in ms], typeof(f).name.mt)
977980
end
@@ -1533,7 +1536,7 @@ function isambiguous(m1::Method, m2::Method; ambiguous_bottom::Bool=false)
15331536
min = UInt[typemin(UInt)]
15341537
max = UInt[typemax(UInt)]
15351538
has_ambig = Int32[0]
1536-
ms = _methods_by_ftype(ti, -1, typemax(UInt), true, min, max, has_ambig)::Vector
1539+
ms = _methods_by_ftype(ti, nothing, -1, typemax(UInt), true, min, max, has_ambig)::Vector
15371540
has_ambig[] == 0 && return false
15381541
if !ambiguous_bottom
15391542
filter!(ms) do m::Core.MethodMatch

src/codegen.cpp

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ static const auto jlinvoke_func = new JuliaFunction{
566566
static const auto jlmethod_func = new JuliaFunction{
567567
"jl_method_def",
568568
[](LLVMContext &C) { return FunctionType::get(T_prjlvalue,
569-
{T_prjlvalue, T_prjlvalue, T_pjlvalue}, false); },
569+
{T_prjlvalue, T_prjlvalue, T_prjlvalue, T_pjlvalue}, false); },
570570
nullptr,
571571
};
572572
static const auto jlgenericfunction_func = new JuliaFunction{
@@ -4398,58 +4398,62 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval)
43984398
return emit_sparam(ctx, jl_unbox_long(args[0]) - 1);
43994399
}
44004400
else if (head == method_sym) {
4401-
jl_value_t *mn = args[0];
4402-
assert(jl_expr_nargs(ex) != 1 || jl_is_symbol(mn) || jl_is_slot(mn));
4401+
if (jl_expr_nargs(ex) == 1) {
4402+
jl_value_t *mn = args[0];
4403+
assert(jl_expr_nargs(ex) != 1 || jl_is_symbol(mn) || jl_is_slot(mn));
44034404

4404-
Value *bp = NULL, *name, *bp_owner = V_null;
4405-
jl_binding_t *bnd = NULL;
4406-
bool issym = jl_is_symbol(mn);
4407-
bool isglobalref = !issym && jl_is_globalref(mn);
4408-
jl_module_t *mod = ctx.module;
4409-
if (issym || isglobalref) {
4410-
if (isglobalref) {
4411-
mod = jl_globalref_mod(mn);
4412-
mn = (jl_value_t*)jl_globalref_name(mn);
4413-
}
4414-
JL_TRY {
4415-
if (jl_symbol_name((jl_sym_t*)mn)[0] == '@')
4416-
jl_errorf("macro definition not allowed inside a local scope");
4417-
name = literal_pointer_val(ctx, mn);
4418-
bnd = jl_get_binding_for_method_def(mod, (jl_sym_t*)mn);
4419-
}
4420-
JL_CATCH {
4421-
jl_value_t *e = jl_current_exception();
4422-
// errors. boo. root it somehow :(
4423-
bnd = jl_get_binding_wr(ctx.module, (jl_sym_t*)jl_gensym(), 1);
4424-
bnd->value = e;
4425-
bnd->constp = 1;
4426-
raise_exception(ctx, literal_pointer_val(ctx, e));
4427-
return ghostValue(jl_nothing_type);
4428-
}
4429-
bp = julia_binding_gv(ctx, bnd);
4430-
bp_owner = literal_pointer_val(ctx, (jl_value_t*)mod);
4431-
}
4432-
else if (jl_is_slot(mn) || jl_is_argument(mn)) {
4433-
int sl = jl_slot_number(mn)-1;
4434-
jl_varinfo_t &vi = ctx.slots[sl];
4435-
bp = vi.boxroot;
4436-
name = literal_pointer_val(ctx, (jl_value_t*)slot_symbol(ctx, sl));
4437-
}
4438-
if (bp) {
4439-
Value *mdargs[5] = { name, literal_pointer_val(ctx, (jl_value_t*)mod), bp,
4440-
bp_owner, literal_pointer_val(ctx, bnd) };
4441-
jl_cgval_t gf = mark_julia_type(
4442-
ctx,
4443-
ctx.builder.CreateCall(prepare_call(jlgenericfunction_func), makeArrayRef(mdargs)),
4444-
true,
4445-
jl_function_type);
4446-
if (jl_expr_nargs(ex) == 1)
4405+
Value *bp = NULL, *name, *bp_owner = V_null;
4406+
jl_binding_t *bnd = NULL;
4407+
bool issym = jl_is_symbol(mn);
4408+
bool isglobalref = !issym && jl_is_globalref(mn);
4409+
jl_module_t *mod = ctx.module;
4410+
if (issym || isglobalref) {
4411+
if (isglobalref) {
4412+
mod = jl_globalref_mod(mn);
4413+
mn = (jl_value_t*)jl_globalref_name(mn);
4414+
}
4415+
JL_TRY {
4416+
if (jl_symbol_name((jl_sym_t*)mn)[0] == '@')
4417+
jl_errorf("macro definition not allowed inside a local scope");
4418+
name = literal_pointer_val(ctx, mn);
4419+
bnd = jl_get_binding_for_method_def(mod, (jl_sym_t*)mn);
4420+
}
4421+
JL_CATCH {
4422+
jl_value_t *e = jl_current_exception();
4423+
// errors. boo. root it somehow :(
4424+
bnd = jl_get_binding_wr(ctx.module, (jl_sym_t*)jl_gensym(), 1);
4425+
bnd->value = e;
4426+
bnd->constp = 1;
4427+
raise_exception(ctx, literal_pointer_val(ctx, e));
4428+
return ghostValue(jl_nothing_type);
4429+
}
4430+
bp = julia_binding_gv(ctx, bnd);
4431+
bp_owner = literal_pointer_val(ctx, (jl_value_t*)mod);
4432+
}
4433+
else if (jl_is_slot(mn) || jl_is_argument(mn)) {
4434+
int sl = jl_slot_number(mn)-1;
4435+
jl_varinfo_t &vi = ctx.slots[sl];
4436+
bp = vi.boxroot;
4437+
name = literal_pointer_val(ctx, (jl_value_t*)slot_symbol(ctx, sl));
4438+
}
4439+
if (bp) {
4440+
Value *mdargs[5] = { name, literal_pointer_val(ctx, (jl_value_t*)mod), bp,
4441+
bp_owner, literal_pointer_val(ctx, bnd) };
4442+
jl_cgval_t gf = mark_julia_type(
4443+
ctx,
4444+
ctx.builder.CreateCall(prepare_call(jlgenericfunction_func), makeArrayRef(mdargs)),
4445+
true,
4446+
jl_function_type);
44474447
return gf;
4448+
}
4449+
emit_error(ctx, "method: invalid declaration");
4450+
return jl_cgval_t();
44484451
}
44494452
Value *a1 = boxed(ctx, emit_expr(ctx, args[1]));
44504453
Value *a2 = boxed(ctx, emit_expr(ctx, args[2]));
4451-
Value *mdargs[3] = {
4454+
Value *mdargs[4] = {
44524455
/*argdata*/a1,
4456+
ConstantPointerNull::get(cast<PointerType>(T_prjlvalue)),
44534457
/*code*/a2,
44544458
/*module*/literal_pointer_val(ctx, (jl_value_t*)ctx.module)
44554459
};

src/dump.c

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,11 @@ static void jl_serialize_code_instance(jl_serializer_state *s, jl_code_instance_
504504
jl_serialize_code_instance(s, codeinst->next, skip_partial_opaque);
505505
}
506506

507+
enum METHOD_SERIALIZATION_MODE {
508+
METHOD_INTERNAL = 1,
509+
METHOD_EXTERNAL_MT = 2,
510+
};
511+
507512
static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_literal) JL_GC_DISABLED
508513
{
509514
if (jl_serialize_generic(s, v)) {
@@ -627,18 +632,34 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li
627632
else if (jl_is_method(v)) {
628633
write_uint8(s->s, TAG_METHOD);
629634
jl_method_t *m = (jl_method_t*)v;
630-
int internal = 1;
631-
internal = m->is_for_opaque_closure || module_in_worklist(m->module);
632-
if (!internal) {
635+
int serialization_mode = 0;
636+
if (m->is_for_opaque_closure || module_in_worklist(m->module))
637+
serialization_mode |= METHOD_INTERNAL;
638+
if (!(serialization_mode & METHOD_INTERNAL)) {
633639
// flag this in the backref table as special
634640
uintptr_t *bp = (uintptr_t*)ptrhash_bp(&backref_table, v);
635641
assert(*bp != (uintptr_t)HT_NOTFOUND);
636642
*bp |= 1;
637643
}
638644
jl_serialize_value(s, (jl_value_t*)m->sig);
639645
jl_serialize_value(s, (jl_value_t*)m->module);
640-
write_uint8(s->s, internal);
641-
if (!internal)
646+
if (m->external_mt != NULL) {
647+
assert(jl_typeis(m->external_mt, jl_methtable_type));
648+
jl_methtable_t *mt = (jl_methtable_t*)m->external_mt;
649+
if (!module_in_worklist(mt->module)) {
650+
serialization_mode |= METHOD_EXTERNAL_MT;
651+
}
652+
}
653+
write_uint8(s->s, serialization_mode);
654+
if (serialization_mode & METHOD_EXTERNAL_MT) {
655+
// We reference this method table by module and binding
656+
jl_methtable_t *mt = (jl_methtable_t*)m->external_mt;
657+
jl_serialize_value(s, mt->module);
658+
jl_serialize_value(s, mt->name);
659+
} else {
660+
jl_serialize_value(s, (jl_value_t*)m->external_mt);
661+
}
662+
if (!(serialization_mode & METHOD_INTERNAL))
642663
return;
643664
jl_serialize_value(s, m->specializations);
644665
jl_serialize_value(s, m->speckeyset);
@@ -952,6 +973,10 @@ static void jl_collect_lambdas_from_mod(jl_array_t *s, jl_module_t *m) JL_GC_DIS
952973
jl_collect_lambdas_from_mod(s, (jl_module_t*)b->value);
953974
}
954975
}
976+
else if (jl_is_mtable(bv)) {
977+
// a module containing an external method table
978+
jl_collect_methtable_from_mod(s, (jl_methtable_t*)bv);
979+
}
955980
}
956981
}
957982
}
@@ -1015,7 +1040,7 @@ static void jl_collect_backedges(jl_array_t *s, jl_array_t *t)
10151040
size_t min_valid = 0;
10161041
size_t max_valid = ~(size_t)0;
10171042
int ambig = 0;
1018-
jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, -1, 0, jl_world_counter, &min_valid, &max_valid, &ambig);
1043+
jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, jl_nothing, -1, 0, jl_world_counter, &min_valid, &max_valid, &ambig);
10191044
if (matches == jl_false) {
10201045
valid = 0;
10211046
break;
@@ -1458,8 +1483,18 @@ static jl_value_t *jl_deserialize_value_method(jl_serializer_state *s, jl_value_
14581483
jl_gc_wb(m, m->sig);
14591484
m->module = (jl_module_t*)jl_deserialize_value(s, (jl_value_t**)&m->module);
14601485
jl_gc_wb(m, m->module);
1461-
int internal = read_uint8(s->s);
1462-
if (!internal) {
1486+
int serialization_mode = read_uint8(s->s);
1487+
if (serialization_mode & METHOD_EXTERNAL_MT) {
1488+
jl_module_t *mt_mod = (jl_module_t*)jl_deserialize_value(s, NULL);
1489+
jl_sym_t *mt_name = (jl_sym_t*)jl_deserialize_value(s, NULL);
1490+
m->external_mt = jl_get_global(mt_mod, mt_name);
1491+
jl_gc_wb(m, m->external_mt);
1492+
assert(jl_typeis(m->external_mt, jl_methtable_type));
1493+
} else {
1494+
m->external_mt = jl_deserialize_value(s, &m->external_mt);
1495+
jl_gc_wb(m, m->external_mt);
1496+
}
1497+
if (!(serialization_mode & METHOD_INTERNAL)) {
14631498
assert(loc != NULL && loc != HT_NOTFOUND);
14641499
arraylist_push(&flagref_list, loc);
14651500
arraylist_push(&flagref_list, (void*)pos);
@@ -1897,7 +1932,7 @@ static void jl_insert_methods(jl_array_t *list)
18971932
assert(!meth->is_for_opaque_closure);
18981933
jl_tupletype_t *simpletype = (jl_tupletype_t*)jl_array_ptr_ref(list, i + 1);
18991934
assert(jl_is_method(meth));
1900-
jl_methtable_t *mt = jl_method_table_for((jl_value_t*)meth->sig);
1935+
jl_methtable_t *mt = jl_method_get_table(meth);
19011936
assert((jl_value_t*)mt != jl_nothing);
19021937
jl_method_table_insert(mt, meth, simpletype);
19031938
}
@@ -1927,7 +1962,7 @@ static void jl_verify_edges(jl_array_t *targets, jl_array_t **pvalids)
19271962
size_t max_valid = ~(size_t)0;
19281963
int ambig = 0;
19291964
// TODO: possibly need to included ambiguities too (for the optimizer correctness)?
1930-
jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, -1, 0, jl_world_counter, &min_valid, &max_valid, &ambig);
1965+
jl_value_t *matches = jl_matching_methods((jl_tupletype_t*)sig, jl_nothing, -1, 0, jl_world_counter, &min_valid, &max_valid, &ambig);
19311966
if (matches == jl_false || jl_array_len(matches) != jl_array_len(expected)) {
19321967
valid = 0;
19331968
}
@@ -2465,7 +2500,7 @@ static jl_method_t *jl_recache_method(jl_method_t *m)
24652500
{
24662501
assert(!m->is_for_opaque_closure);
24672502
jl_datatype_t *sig = (jl_datatype_t*)m->sig;
2468-
jl_methtable_t *mt = jl_method_table_for((jl_value_t*)m->sig);
2503+
jl_methtable_t *mt = jl_method_get_table(m);
24692504
assert((jl_value_t*)mt != jl_nothing);
24702505
jl_set_typeof(m, (void*)(intptr_t)0x30); // invalidate the old value to help catch errors
24712506
jl_method_t *_new = jl_lookup_method(mt, sig, m->module->primary_world);

0 commit comments

Comments
 (0)