Skip to content

Commit 92197a7

Browse files
authored
Merge pull request #36166 from JuliaLang/jn/ml-matches-leaf-cache
Create a leaf-types cache (so we'll first hit the call-site cache LRU, then the TypeMap search, then this hash lookup, before going to the defs list), and use this new cache for the ml-matches search also (when applicable/useful).
2 parents 4d062a5 + 6c54523 commit 92197a7

16 files changed

+273
-167
lines changed

base/errorshow.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ function showerror(io::IO, ex::InexactError)
176176
Experimental.show_error_hints(io, ex)
177177
end
178178

179-
typesof(args...) = Tuple{Any[ Core.Typeof(a) for a in args ]...}
179+
typesof(@nospecialize args...) = Tuple{Any[ Core.Typeof(args[i]) for i in 1:length(args) ]...}
180180

181181
function print_with_compare(io::IO, @nospecialize(a::DataType), @nospecialize(b::DataType), color::Symbol)
182182
if a.name === b.name

src/ast.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule
962962
jl_value_t *result;
963963
JL_TRY {
964964
margs[0] = jl_toplevel_eval(*ctx, margs[0]);
965-
jl_method_instance_t *mfunc = jl_method_lookup(margs, nargs, 1, world);
965+
jl_method_instance_t *mfunc = jl_method_lookup(margs, nargs, world);
966966
JL_GC_PROMISE_ROOTED(mfunc);
967967
if (mfunc == NULL) {
968968
jl_method_error(margs[0], &margs[1], nargs, world);

src/builtins.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -990,8 +990,7 @@ JL_CALLABLE(jl_f_applicable)
990990
{
991991
JL_NARGSV(applicable, 1);
992992
size_t world = jl_get_ptls_states()->world_age;
993-
return jl_method_lookup(args, nargs, 1, world) != NULL ?
994-
jl_true : jl_false;
993+
return jl_method_lookup(args, nargs, world) != NULL ? jl_true : jl_false;
995994
}
996995

997996
JL_CALLABLE(jl_f_invoke)

src/datatype.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *mo
4949
mt->name = jl_demangle_typename(name);
5050
mt->module = module;
5151
mt->defs = jl_nothing;
52+
mt->leafcache = (jl_array_t*)jl_an_empty_vec_any;
5253
mt->cache = jl_nothing;
5354
mt->max_args = 0;
5455
mt->kwsorter = NULL;

src/dump.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,9 +2237,6 @@ STATIC_INLINE jl_value_t *verify_type(jl_value_t *v) JL_NOTSAFEPOINT
22372237
}
22382238
#endif
22392239

2240-
jl_datatype_t *jl_lookup_cache_type_(jl_datatype_t *type);
2241-
void jl_cache_type_(jl_datatype_t *type);
2242-
22432240
static jl_datatype_t *jl_recache_type(jl_datatype_t *dt) JL_GC_DISABLED
22442241
{
22452242
jl_datatype_t *t; // the type after unique'ing

src/gf.c

Lines changed: 196 additions & 86 deletions
Large diffs are not rendered by default.

src/iddict.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ static int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_t *val)
3737
jl_array_t *a = *pa;
3838
size_t orig, index, iter, empty_slot;
3939
size_t newsz, sz = hash_size(a);
40-
assert(sz >= 1);
40+
if (sz == 0) {
41+
a = jl_alloc_vec_any(HT_N_INLINE);
42+
sz = hash_size(a);
43+
*pa = a;
44+
}
4145
size_t maxprobe = max_probe(sz);
4246
void **tab = (void **)a->data;
4347

@@ -108,7 +112,8 @@ static int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_t *val)
108112
jl_value_t **jl_table_peek_bp(jl_array_t *a, jl_value_t *key) JL_NOTSAFEPOINT
109113
{
110114
size_t sz = hash_size(a);
111-
assert(sz >= 1);
115+
if (sz == 0)
116+
return NULL;
112117
size_t maxprobe = max_probe(sz);
113118
void **tab = (void **)a->data;
114119
uint_t hv = keyhash(key);

src/init.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,6 @@ void _julia_init(JL_IMAGE_SEARCH rel)
721721
else {
722722
jl_init_types();
723723
jl_init_codegen();
724-
jl_an_empty_vec_any = (jl_value_t*)jl_alloc_vec_any(0); // used internally
725724
}
726725

727726
jl_init_tasks();

src/jltypes.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -822,17 +822,9 @@ static void cache_insert_type_linear(jl_datatype_t *type, ssize_t insert_at)
822822
#ifndef NDEBUG
823823
static int is_cacheable(jl_datatype_t *type)
824824
{
825-
// only cache types whose behavior will not depend on the identities
826-
// of contained TypeVars
827-
assert(jl_is_datatype(type));
828-
jl_svec_t *t = type->parameters;
829-
if (jl_svec_len(t) == 0 && jl_emptytuple_type != NULL) // Tuple{} is the only type eligible for this that doesn't have parameters
830-
return 0;
831-
// cache abstract types with no free type vars
832-
if (jl_is_abstracttype(type))
833-
return !jl_has_free_typevars((jl_value_t*)type);
834-
// ... or concrete types
835-
return jl_is_concrete_type((jl_value_t*)type);
825+
// ensure cache only contains types whose behavior will not depend on the
826+
// identities of contained TypeVars
827+
return !jl_has_free_typevars((jl_value_t*)type);
836828
}
837829
#endif
838830

@@ -1943,18 +1935,19 @@ void jl_init_types(void) JL_GC_DISABLED
19431935
jl_methtable_type->name->mt = jl_nonfunction_mt;
19441936
jl_methtable_type->super = jl_any_type;
19451937
jl_methtable_type->parameters = jl_emptysvec;
1946-
jl_methtable_type->name->names = jl_perm_symsvec(11, "name", "defs",
1947-
"cache", "max_args",
1938+
jl_methtable_type->name->names = jl_perm_symsvec(12, "name", "defs",
1939+
"leafcache", "cache", "max_args",
19481940
"kwsorter", "module",
19491941
"backedges", "", "", "offs", "");
1950-
jl_methtable_type->types = jl_svec(11, jl_symbol_type, jl_any_type, jl_any_type, jl_any_type/*jl_long*/,
1942+
jl_methtable_type->types = jl_svec(12, jl_symbol_type, jl_any_type, jl_any_type,
1943+
jl_any_type, jl_any_type/*jl_long*/,
19511944
jl_any_type, jl_any_type/*module*/,
19521945
jl_any_type/*any vector*/, jl_any_type/*long*/, jl_any_type/*int32*/,
19531946
jl_any_type/*uint8*/, jl_any_type/*uint8*/);
19541947
jl_methtable_type->instance = NULL;
19551948
jl_methtable_type->abstract = 0;
19561949
jl_methtable_type->mutabl = 1;
1957-
jl_methtable_type->ninitialized = 4;
1950+
jl_methtable_type->ninitialized = 5;
19581951
jl_precompute_memoized_dt(jl_methtable_type, 1);
19591952

19601953
jl_symbol_type->name = jl_new_typename_in(jl_symbol("Symbol"), core);
@@ -2152,6 +2145,9 @@ void jl_init_types(void) JL_GC_DISABLED
21522145
jl_array_symbol_type = jl_apply_type2((jl_value_t*)jl_array_type, (jl_value_t*)jl_symbol_type, jl_box_long(1));
21532146
jl_array_uint8_type = jl_apply_type2((jl_value_t*)jl_array_type, (jl_value_t*)jl_uint8_type, jl_box_long(1));
21542147
jl_array_int32_type = jl_apply_type2((jl_value_t*)jl_array_type, (jl_value_t*)jl_int32_type, jl_box_long(1));
2148+
jl_an_empty_vec_any = (jl_value_t*)jl_alloc_vec_any(0); // used internally
2149+
jl_nonfunction_mt->leafcache = (jl_array_t*)jl_an_empty_vec_any;
2150+
jl_type_type_mt->leafcache = (jl_array_t*)jl_an_empty_vec_any;
21552151

21562152
jl_expr_type =
21572153
jl_new_datatype(jl_symbol("Expr"), core,
@@ -2466,18 +2462,18 @@ void jl_init_types(void) JL_GC_DISABLED
24662462
jl_svecset(jl_typename_type->types, 1, jl_module_type);
24672463
jl_svecset(jl_typename_type->types, 6, jl_long_type);
24682464
jl_svecset(jl_typename_type->types, 3, jl_type_type);
2469-
jl_svecset(jl_methtable_type->types, 3, jl_long_type);
2470-
jl_svecset(jl_methtable_type->types, 5, jl_module_type);
2471-
jl_svecset(jl_methtable_type->types, 6, jl_array_any_type);
2465+
jl_svecset(jl_methtable_type->types, 4, jl_long_type);
2466+
jl_svecset(jl_methtable_type->types, 6, jl_module_type);
2467+
jl_svecset(jl_methtable_type->types, 7, jl_array_any_type);
24722468
#ifdef __LP64__
2473-
jl_svecset(jl_methtable_type->types, 7, jl_int64_type); // unsigned long
2474-
jl_svecset(jl_methtable_type->types, 8, jl_int64_type); // uint32_t plus alignment
2469+
jl_svecset(jl_methtable_type->types, 8, jl_int64_type); // unsigned long
2470+
jl_svecset(jl_methtable_type->types, 9, jl_int64_type); // uint32_t plus alignment
24752471
#else
2476-
jl_svecset(jl_methtable_type->types, 7, jl_int32_type); // DWORD
2477-
jl_svecset(jl_methtable_type->types, 8, jl_int32_type); // uint32_t
2472+
jl_svecset(jl_methtable_type->types, 8, jl_int32_type); // DWORD
2473+
jl_svecset(jl_methtable_type->types, 9, jl_int32_type); // uint32_t
24782474
#endif
2479-
jl_svecset(jl_methtable_type->types, 9, jl_uint8_type);
24802475
jl_svecset(jl_methtable_type->types, 10, jl_uint8_type);
2476+
jl_svecset(jl_methtable_type->types, 11, jl_uint8_type);
24812477
jl_svecset(jl_method_type->types, 13, jl_method_instance_type);
24822478
jl_svecset(jl_method_instance_type->types, 5, jl_code_instance_type);
24832479
jl_svecset(jl_code_instance_type->types, 8, jl_voidpointer_type);

src/julia.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ typedef struct _jl_methtable_t {
537537
JL_DATA_TYPE
538538
jl_sym_t *name; // sometimes a hack used by serialization to handle kwsorter
539539
jl_typemap_t *defs;
540+
jl_array_t *leafcache;
540541
jl_typemap_t *cache;
541542
intptr_t max_args; // max # of non-vararg arguments in a signature
542543
jl_value_t *kwsorter; // keyword argument sorter function

src/julia_internal.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,8 @@ jl_datatype_t *jl_new_uninitialized_datatype(void);
462462
void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable);
463463
jl_datatype_t *jl_wrap_Type(jl_value_t *t); // x -> Type{x}
464464
jl_value_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n);
465+
jl_datatype_t *jl_lookup_cache_type_(jl_datatype_t *type);
466+
void jl_cache_type_(jl_datatype_t *type);
465467
void jl_assign_bits(void *dest, jl_value_t *bits) JL_NOTSAFEPOINT;
466468
void set_nth_field(jl_datatype_t *st, void *v, size_t i, jl_value_t *rhs) JL_NOTSAFEPOINT;
467469
jl_expr_t *jl_exprn(jl_sym_t *head, size_t n);
@@ -482,7 +484,7 @@ int jl_is_toplevel_only_expr(jl_value_t *e) JL_NOTSAFEPOINT;
482484
jl_value_t *jl_call_scm_on_ast(const char *funcname, jl_value_t *expr, jl_module_t *inmodule);
483485
void jl_linenumber_to_lineinfo(jl_code_info_t *ci, jl_value_t *name);
484486

485-
jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t nargs, int cache, size_t world);
487+
jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t nargs, size_t world);
486488
jl_value_t *jl_gf_invoke(jl_value_t *types, jl_value_t *f, jl_value_t **args, size_t nargs);
487489
jl_method_instance_t *jl_lookup_generic(jl_value_t **args, uint32_t nargs, uint32_t callsite, size_t world) JL_ALWAYS_LEAFTYPE;
488490
JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, int lim, int include_ambiguous,
@@ -1047,13 +1049,12 @@ struct jl_typemap_info {
10471049
jl_datatype_t **jl_contains; // the type that is being put in this
10481050
};
10491051

1050-
jl_typemap_entry_t *jl_typemap_insert(jl_typemap_t **cache,
1051-
jl_value_t *parent JL_PROPAGATES_ROOT,
1052-
jl_tupletype_t *type,
1053-
jl_tupletype_t *simpletype, jl_svec_t *guardsigs,
1054-
jl_value_t *newvalue, int8_t offs,
1055-
const struct jl_typemap_info *tparams,
1056-
size_t min_world, size_t max_world);
1052+
void jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent,
1053+
jl_typemap_entry_t *newrec, int8_t offs,
1054+
const struct jl_typemap_info *tparams);
1055+
jl_typemap_entry_t *jl_typemap_alloc(
1056+
jl_tupletype_t *type, jl_tupletype_t *simpletype, jl_svec_t *guardsigs,
1057+
jl_value_t *newvalue, size_t min_world, size_t max_world);
10571058

10581059
struct jl_typemap_assoc {
10591060
// inputs

src/precompile.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,12 +314,6 @@ static void jl_compile_all_defs(void)
314314
JL_GC_POP();
315315
}
316316

317-
static int precompile_enq_all_cache__(jl_typemap_entry_t *l, void *closure)
318-
{
319-
jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)l->func.linfo);
320-
return 1;
321-
}
322-
323317
static int precompile_enq_specialization_(jl_method_instance_t *mi, void *closure)
324318
{
325319
assert(jl_is_method_instance(mi));
@@ -370,7 +364,6 @@ static int precompile_enq_all_specializations__(jl_typemap_entry_t *def, void *c
370364
static void precompile_enq_all_specializations_(jl_methtable_t *mt, void *env)
371365
{
372366
jl_typemap_visitor(mt->defs, precompile_enq_all_specializations__, env);
373-
jl_typemap_visitor(mt->cache, precompile_enq_all_cache__, env);
374367
}
375368

376369
void jl_compile_now(jl_method_instance_t *mi);

src/typemap.c

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -872,18 +872,34 @@ static void jl_typemap_level_insert_(
872872
jl_typemap_list_insert_(map, &cache->linear, (jl_value_t*)cache, newrec, tparams);
873873
}
874874

875-
jl_typemap_entry_t *jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent,
876-
jl_tupletype_t *type,
877-
jl_tupletype_t *simpletype, jl_svec_t *guardsigs,
878-
jl_value_t *newvalue, int8_t offs,
879-
const struct jl_typemap_info *tparams,
880-
size_t min_world, size_t max_world)
875+
jl_typemap_entry_t *jl_typemap_alloc(
876+
jl_tupletype_t *type, jl_tupletype_t *simpletype, jl_svec_t *guardsigs,
877+
jl_value_t *newvalue, size_t min_world, size_t max_world)
881878
{
882879
jl_ptls_t ptls = jl_get_ptls_states();
883880
assert(min_world > 0 && max_world > 0);
884881
if (!simpletype)
885882
simpletype = (jl_tupletype_t*)jl_nothing;
886883
jl_value_t *ttype = jl_unwrap_unionall((jl_value_t*)type);
884+
assert(jl_is_tuple_type(ttype));
885+
// compute the complexity of this type signature
886+
int isva = jl_is_va_tuple((jl_datatype_t*)ttype);
887+
int issimplesig = !jl_is_unionall(type); // a TypeVar environment needs a complex matching test
888+
int isleafsig = issimplesig && !isva; // entirely leaf types don't need to be sorted
889+
size_t i, l;
890+
for (i = 0, l = jl_nparams(ttype); i < l && issimplesig; i++) {
891+
jl_value_t *decl = jl_tparam(ttype, i);
892+
if (jl_is_kind(decl))
893+
isleafsig = 0; // Type{} may have a higher priority than a kind
894+
else if (jl_is_type_type(decl))
895+
isleafsig = 0; // Type{} may need special processing to compute the match
896+
else if (jl_is_vararg_type(decl))
897+
isleafsig = 0; // makes iteration easier when the endpoints are the same
898+
else if (decl == (jl_value_t*)jl_any_type)
899+
isleafsig = 0; // Any needs to go in the general cache
900+
else if (!jl_is_concrete_type(decl)) // anything else needs to go through the general subtyping test
901+
isleafsig = issimplesig = 0;
902+
}
887903

888904
jl_typemap_entry_t *newrec =
889905
(jl_typemap_entry_t*)jl_gc_alloc(ptls, sizeof(jl_typemap_entry_t),
@@ -895,32 +911,19 @@ jl_typemap_entry_t *jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent,
895911
newrec->next = (jl_typemap_entry_t*)jl_nothing;
896912
newrec->min_world = min_world;
897913
newrec->max_world = max_world;
898-
// compute the complexity of this type signature
899-
newrec->va = jl_is_va_tuple((jl_datatype_t*)ttype);
900-
newrec->issimplesig = !jl_is_unionall(type); // a TypeVar environment needs a complex matching test
901-
newrec->isleafsig = newrec->issimplesig && !newrec->va; // entirely leaf types don't need to be sorted
902-
JL_GC_PUSH1(&newrec);
903-
assert(jl_is_tuple_type(ttype));
904-
size_t i, l;
905-
for (i = 0, l = jl_nparams(ttype); i < l && newrec->issimplesig; i++) {
906-
jl_value_t *decl = jl_tparam(ttype, i);
907-
if (jl_is_kind(decl))
908-
newrec->isleafsig = 0; // Type{} may have a higher priority than a kind
909-
else if (jl_is_type_type(decl))
910-
newrec->isleafsig = 0; // Type{} may need special processing to compute the match
911-
else if (jl_is_vararg_type(decl))
912-
newrec->isleafsig = 0; // makes iteration easier when the endpoints are the same
913-
else if (decl == (jl_value_t*)jl_any_type)
914-
newrec->isleafsig = 0; // Any needs to go in the general cache
915-
else if (!jl_is_concrete_type(decl)) // anything else needs to go through the general subtyping test
916-
newrec->isleafsig = newrec->issimplesig = 0;
917-
}
918-
// TODO: assert that guardsigs == jl_emptysvec && simplesig == jl_nothing if isleafsig and optimize with that knowledge?
919-
jl_typemap_insert_generic(*cache, cache, parent, newrec, offs, tparams);
920-
JL_GC_POP();
914+
newrec->va = isva;
915+
newrec->issimplesig = issimplesig;
916+
newrec->isleafsig = isleafsig;
921917
return newrec;
922918
}
923919

920+
void jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent,
921+
jl_typemap_entry_t *newrec, int8_t offs,
922+
const struct jl_typemap_info *tparams)
923+
{
924+
jl_typemap_insert_generic(*cache, cache, parent, newrec, offs, tparams);
925+
}
926+
924927
static void jl_typemap_list_insert_sorted(
925928
jl_typemap_t *map, jl_typemap_entry_t **pml, jl_value_t *parent,
926929
jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams)

stdlib/REPL/src/REPLCompletions.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,15 +397,15 @@ end
397397
# Returns the return type. example: get_type(:(Base.strip("", ' ')), Main) returns (String, true)
398398
function try_get_type(sym::Expr, fn::Module)
399399
val, found = get_value(sym, fn)
400-
found && return Base.typesof(val).parameters[1], found
400+
found && return Core.Typeof(val), found
401401
if sym.head === :call
402402
# getfield call is special cased as the evaluation of getfield provides good type information,
403403
# is inexpensive and it is also performed in the complete_symbol function.
404404
a1 = sym.args[1]
405405
if isa(a1,GlobalRef) && isconst(a1.mod,a1.name) && isdefined(a1.mod,a1.name) &&
406406
eval(a1) === Core.getfield
407407
val, found = get_value_getfield(sym, Main)
408-
return found ? Base.typesof(val).parameters[1] : Any, found
408+
return found ? Core.Typeof(val) : Any, found
409409
end
410410
return get_type_call(sym)
411411
elseif sym.head === :thunk
@@ -432,7 +432,7 @@ end
432432

433433
function get_type(sym, fn::Module)
434434
val, found = get_value(sym, fn)
435-
return found ? Base.typesof(val).parameters[1] : Any, found
435+
return found ? Core.Typeof(val) : Any, found
436436
end
437437

438438
# Method completion on function call expression that look like :(max(1))

test/channels.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ end
390390
t = Timer(0) do t
391391
tc[] += 1
392392
end
393+
Libc.systemsleep(0.005)
393394
@test isopen(t)
394395
Base.process_events()
395396
@test !isopen(t)
@@ -402,6 +403,7 @@ end
402403
t = Timer(0) do t
403404
tc[] += 1
404405
end
406+
Libc.systemsleep(0.005)
405407
@test isopen(t)
406408
close(t)
407409
@test !isopen(t)

test/reflection.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,6 @@ f18888() = nothing
507507
let
508508
world = Core.Compiler.get_world_counter()
509509
m = first(methods(f18888, Tuple{}))
510-
@test isempty(m.specializations)
511510
ft = typeof(f18888)
512511

513512
code_typed(f18888, Tuple{}; optimize=false)

0 commit comments

Comments
 (0)