Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

leaf-types cache for ml-matches #36166

Merged
merged 6 commits into from
Jun 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ function showerror(io::IO, ex::InexactError)
Experimental.show_error_hints(io, ex)
end

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

function print_with_compare(io::IO, @nospecialize(a::DataType), @nospecialize(b::DataType), color::Symbol)
if a.name === b.name
Expand Down
2 changes: 1 addition & 1 deletion src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@ static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule
jl_value_t *result;
JL_TRY {
margs[0] = jl_toplevel_eval(*ctx, margs[0]);
jl_method_instance_t *mfunc = jl_method_lookup(margs, nargs, 1, world);
jl_method_instance_t *mfunc = jl_method_lookup(margs, nargs, world);
JL_GC_PROMISE_ROOTED(mfunc);
if (mfunc == NULL) {
jl_method_error(margs[0], &margs[1], nargs, world);
Expand Down
3 changes: 1 addition & 2 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -990,8 +990,7 @@ JL_CALLABLE(jl_f_applicable)
{
JL_NARGSV(applicable, 1);
size_t world = jl_get_ptls_states()->world_age;
return jl_method_lookup(args, nargs, 1, world) != NULL ?
jl_true : jl_false;
return jl_method_lookup(args, nargs, world) != NULL ? jl_true : jl_false;
}

JL_CALLABLE(jl_f_invoke)
Expand Down
1 change: 1 addition & 0 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *mo
mt->name = jl_demangle_typename(name);
mt->module = module;
mt->defs = jl_nothing;
mt->leafcache = (jl_array_t*)jl_an_empty_vec_any;
mt->cache = jl_nothing;
mt->max_args = 0;
mt->kwsorter = NULL;
Expand Down
3 changes: 0 additions & 3 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -2237,9 +2237,6 @@ STATIC_INLINE jl_value_t *verify_type(jl_value_t *v) JL_NOTSAFEPOINT
}
#endif

jl_datatype_t *jl_lookup_cache_type_(jl_datatype_t *type);
void jl_cache_type_(jl_datatype_t *type);

static jl_datatype_t *jl_recache_type(jl_datatype_t *dt) JL_GC_DISABLED
{
jl_datatype_t *t; // the type after unique'ing
Expand Down
282 changes: 196 additions & 86 deletions src/gf.c

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions src/iddict.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ static int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_t *val)
jl_array_t *a = *pa;
size_t orig, index, iter, empty_slot;
size_t newsz, sz = hash_size(a);
assert(sz >= 1);
if (sz == 0) {
a = jl_alloc_vec_any(HT_N_INLINE);
sz = hash_size(a);
*pa = a;
}
size_t maxprobe = max_probe(sz);
void **tab = (void **)a->data;

Expand Down Expand Up @@ -108,7 +112,8 @@ static int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_t *val)
jl_value_t **jl_table_peek_bp(jl_array_t *a, jl_value_t *key) JL_NOTSAFEPOINT
{
size_t sz = hash_size(a);
assert(sz >= 1);
if (sz == 0)
return NULL;
size_t maxprobe = max_probe(sz);
void **tab = (void **)a->data;
uint_t hv = keyhash(key);
Expand Down
1 change: 0 additions & 1 deletion src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,6 @@ void _julia_init(JL_IMAGE_SEARCH rel)
else {
jl_init_types();
jl_init_codegen();
jl_an_empty_vec_any = (jl_value_t*)jl_alloc_vec_any(0); // used internally
}

jl_init_tasks();
Expand Down
42 changes: 19 additions & 23 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -822,17 +822,9 @@ static void cache_insert_type_linear(jl_datatype_t *type, ssize_t insert_at)
#ifndef NDEBUG
static int is_cacheable(jl_datatype_t *type)
{
// only cache types whose behavior will not depend on the identities
// of contained TypeVars
assert(jl_is_datatype(type));
jl_svec_t *t = type->parameters;
if (jl_svec_len(t) == 0 && jl_emptytuple_type != NULL) // Tuple{} is the only type eligible for this that doesn't have parameters
return 0;
// cache abstract types with no free type vars
if (jl_is_abstracttype(type))
return !jl_has_free_typevars((jl_value_t*)type);
// ... or concrete types
return jl_is_concrete_type((jl_value_t*)type);
// ensure cache only contains types whose behavior will not depend on the
// identities of contained TypeVars
return !jl_has_free_typevars((jl_value_t*)type);
}
#endif

Expand Down Expand Up @@ -1943,18 +1935,19 @@ void jl_init_types(void) JL_GC_DISABLED
jl_methtable_type->name->mt = jl_nonfunction_mt;
jl_methtable_type->super = jl_any_type;
jl_methtable_type->parameters = jl_emptysvec;
jl_methtable_type->name->names = jl_perm_symsvec(11, "name", "defs",
"cache", "max_args",
jl_methtable_type->name->names = jl_perm_symsvec(12, "name", "defs",
"leafcache", "cache", "max_args",
"kwsorter", "module",
"backedges", "", "", "offs", "");
jl_methtable_type->types = jl_svec(11, jl_symbol_type, jl_any_type, jl_any_type, jl_any_type/*jl_long*/,
jl_methtable_type->types = jl_svec(12, jl_symbol_type, jl_any_type, jl_any_type,
jl_any_type, jl_any_type/*jl_long*/,
jl_any_type, jl_any_type/*module*/,
jl_any_type/*any vector*/, jl_any_type/*long*/, jl_any_type/*int32*/,
jl_any_type/*uint8*/, jl_any_type/*uint8*/);
jl_methtable_type->instance = NULL;
jl_methtable_type->abstract = 0;
jl_methtable_type->mutabl = 1;
jl_methtable_type->ninitialized = 4;
jl_methtable_type->ninitialized = 5;
jl_precompute_memoized_dt(jl_methtable_type, 1);

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

jl_expr_type =
jl_new_datatype(jl_symbol("Expr"), core,
Expand Down Expand Up @@ -2466,18 +2462,18 @@ void jl_init_types(void) JL_GC_DISABLED
jl_svecset(jl_typename_type->types, 1, jl_module_type);
jl_svecset(jl_typename_type->types, 6, jl_long_type);
jl_svecset(jl_typename_type->types, 3, jl_type_type);
jl_svecset(jl_methtable_type->types, 3, jl_long_type);
jl_svecset(jl_methtable_type->types, 5, jl_module_type);
jl_svecset(jl_methtable_type->types, 6, jl_array_any_type);
jl_svecset(jl_methtable_type->types, 4, jl_long_type);
jl_svecset(jl_methtable_type->types, 6, jl_module_type);
jl_svecset(jl_methtable_type->types, 7, jl_array_any_type);
#ifdef __LP64__
jl_svecset(jl_methtable_type->types, 7, jl_int64_type); // unsigned long
jl_svecset(jl_methtable_type->types, 8, jl_int64_type); // uint32_t plus alignment
jl_svecset(jl_methtable_type->types, 8, jl_int64_type); // unsigned long
jl_svecset(jl_methtable_type->types, 9, jl_int64_type); // uint32_t plus alignment
#else
jl_svecset(jl_methtable_type->types, 7, jl_int32_type); // DWORD
jl_svecset(jl_methtable_type->types, 8, jl_int32_type); // uint32_t
jl_svecset(jl_methtable_type->types, 8, jl_int32_type); // DWORD
jl_svecset(jl_methtable_type->types, 9, jl_int32_type); // uint32_t
#endif
jl_svecset(jl_methtable_type->types, 9, jl_uint8_type);
jl_svecset(jl_methtable_type->types, 10, jl_uint8_type);
jl_svecset(jl_methtable_type->types, 11, jl_uint8_type);
jl_svecset(jl_method_type->types, 13, jl_method_instance_type);
jl_svecset(jl_method_instance_type->types, 5, jl_code_instance_type);
jl_svecset(jl_code_instance_type->types, 8, jl_voidpointer_type);
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ typedef struct _jl_methtable_t {
JL_DATA_TYPE
jl_sym_t *name; // sometimes a hack used by serialization to handle kwsorter
jl_typemap_t *defs;
jl_array_t *leafcache;
jl_typemap_t *cache;
intptr_t max_args; // max # of non-vararg arguments in a signature
jl_value_t *kwsorter; // keyword argument sorter function
Expand Down
17 changes: 9 additions & 8 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,8 @@ jl_datatype_t *jl_new_uninitialized_datatype(void);
void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable);
jl_datatype_t *jl_wrap_Type(jl_value_t *t); // x -> Type{x}
jl_value_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n);
jl_datatype_t *jl_lookup_cache_type_(jl_datatype_t *type);
void jl_cache_type_(jl_datatype_t *type);
void jl_assign_bits(void *dest, jl_value_t *bits) JL_NOTSAFEPOINT;
void set_nth_field(jl_datatype_t *st, void *v, size_t i, jl_value_t *rhs) JL_NOTSAFEPOINT;
jl_expr_t *jl_exprn(jl_sym_t *head, size_t n);
Expand All @@ -482,7 +484,7 @@ int jl_is_toplevel_only_expr(jl_value_t *e) JL_NOTSAFEPOINT;
jl_value_t *jl_call_scm_on_ast(const char *funcname, jl_value_t *expr, jl_module_t *inmodule);
void jl_linenumber_to_lineinfo(jl_code_info_t *ci, jl_value_t *name);

jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t nargs, int cache, size_t world);
jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t nargs, size_t world);
jl_value_t *jl_gf_invoke(jl_value_t *types, jl_value_t *f, jl_value_t **args, size_t nargs);
jl_method_instance_t *jl_lookup_generic(jl_value_t **args, uint32_t nargs, uint32_t callsite, size_t world) JL_ALWAYS_LEAFTYPE;
JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, int lim, int include_ambiguous,
Expand Down Expand Up @@ -1048,13 +1050,12 @@ struct jl_typemap_info {
jl_datatype_t **jl_contains; // the type that is being put in this
};

jl_typemap_entry_t *jl_typemap_insert(jl_typemap_t **cache,
jl_value_t *parent JL_PROPAGATES_ROOT,
jl_tupletype_t *type,
jl_tupletype_t *simpletype, jl_svec_t *guardsigs,
jl_value_t *newvalue, int8_t offs,
const struct jl_typemap_info *tparams,
size_t min_world, size_t max_world);
void jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent,
jl_typemap_entry_t *newrec, int8_t offs,
const struct jl_typemap_info *tparams);
jl_typemap_entry_t *jl_typemap_alloc(
jl_tupletype_t *type, jl_tupletype_t *simpletype, jl_svec_t *guardsigs,
jl_value_t *newvalue, size_t min_world, size_t max_world);

struct jl_typemap_assoc {
// inputs
Expand Down
7 changes: 0 additions & 7 deletions src/precompile.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,6 @@ static void jl_compile_all_defs(void)
JL_GC_POP();
}

static int precompile_enq_all_cache__(jl_typemap_entry_t *l, void *closure)
{
jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)l->func.linfo);
return 1;
}

static int precompile_enq_specialization_(jl_method_instance_t *mi, void *closure)
{
assert(jl_is_method_instance(mi));
Expand Down Expand Up @@ -370,7 +364,6 @@ static int precompile_enq_all_specializations__(jl_typemap_entry_t *def, void *c
static void precompile_enq_all_specializations_(jl_methtable_t *mt, void *env)
{
jl_typemap_visitor(mt->defs, precompile_enq_all_specializations__, env);
jl_typemap_visitor(mt->cache, precompile_enq_all_cache__, env);
}

void jl_compile_now(jl_method_instance_t *mi);
Expand Down
61 changes: 32 additions & 29 deletions src/typemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -872,18 +872,34 @@ static void jl_typemap_level_insert_(
jl_typemap_list_insert_(map, &cache->linear, (jl_value_t*)cache, newrec, tparams);
}

jl_typemap_entry_t *jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent,
jl_tupletype_t *type,
jl_tupletype_t *simpletype, jl_svec_t *guardsigs,
jl_value_t *newvalue, int8_t offs,
const struct jl_typemap_info *tparams,
size_t min_world, size_t max_world)
jl_typemap_entry_t *jl_typemap_alloc(
jl_tupletype_t *type, jl_tupletype_t *simpletype, jl_svec_t *guardsigs,
jl_value_t *newvalue, size_t min_world, size_t max_world)
{
jl_ptls_t ptls = jl_get_ptls_states();
assert(min_world > 0 && max_world > 0);
if (!simpletype)
simpletype = (jl_tupletype_t*)jl_nothing;
jl_value_t *ttype = jl_unwrap_unionall((jl_value_t*)type);
assert(jl_is_tuple_type(ttype));
// compute the complexity of this type signature
int isva = jl_is_va_tuple((jl_datatype_t*)ttype);
int issimplesig = !jl_is_unionall(type); // a TypeVar environment needs a complex matching test
int isleafsig = issimplesig && !isva; // entirely leaf types don't need to be sorted
size_t i, l;
for (i = 0, l = jl_nparams(ttype); i < l && issimplesig; i++) {
jl_value_t *decl = jl_tparam(ttype, i);
if (jl_is_kind(decl))
isleafsig = 0; // Type{} may have a higher priority than a kind
else if (jl_is_type_type(decl))
isleafsig = 0; // Type{} may need special processing to compute the match
else if (jl_is_vararg_type(decl))
isleafsig = 0; // makes iteration easier when the endpoints are the same
else if (decl == (jl_value_t*)jl_any_type)
isleafsig = 0; // Any needs to go in the general cache
else if (!jl_is_concrete_type(decl)) // anything else needs to go through the general subtyping test
isleafsig = issimplesig = 0;
}

jl_typemap_entry_t *newrec =
(jl_typemap_entry_t*)jl_gc_alloc(ptls, sizeof(jl_typemap_entry_t),
Expand All @@ -895,32 +911,19 @@ jl_typemap_entry_t *jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent,
newrec->next = (jl_typemap_entry_t*)jl_nothing;
newrec->min_world = min_world;
newrec->max_world = max_world;
// compute the complexity of this type signature
newrec->va = jl_is_va_tuple((jl_datatype_t*)ttype);
newrec->issimplesig = !jl_is_unionall(type); // a TypeVar environment needs a complex matching test
newrec->isleafsig = newrec->issimplesig && !newrec->va; // entirely leaf types don't need to be sorted
JL_GC_PUSH1(&newrec);
assert(jl_is_tuple_type(ttype));
size_t i, l;
for (i = 0, l = jl_nparams(ttype); i < l && newrec->issimplesig; i++) {
jl_value_t *decl = jl_tparam(ttype, i);
if (jl_is_kind(decl))
newrec->isleafsig = 0; // Type{} may have a higher priority than a kind
else if (jl_is_type_type(decl))
newrec->isleafsig = 0; // Type{} may need special processing to compute the match
else if (jl_is_vararg_type(decl))
newrec->isleafsig = 0; // makes iteration easier when the endpoints are the same
else if (decl == (jl_value_t*)jl_any_type)
newrec->isleafsig = 0; // Any needs to go in the general cache
else if (!jl_is_concrete_type(decl)) // anything else needs to go through the general subtyping test
newrec->isleafsig = newrec->issimplesig = 0;
}
// TODO: assert that guardsigs == jl_emptysvec && simplesig == jl_nothing if isleafsig and optimize with that knowledge?
jl_typemap_insert_generic(*cache, cache, parent, newrec, offs, tparams);
JL_GC_POP();
newrec->va = isva;
newrec->issimplesig = issimplesig;
newrec->isleafsig = isleafsig;
return newrec;
}

void jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent,
jl_typemap_entry_t *newrec, int8_t offs,
const struct jl_typemap_info *tparams)
{
jl_typemap_insert_generic(*cache, cache, parent, newrec, offs, tparams);
}

static void jl_typemap_list_insert_sorted(
jl_typemap_t *map, jl_typemap_entry_t **pml, jl_value_t *parent,
jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams)
Expand Down
6 changes: 3 additions & 3 deletions stdlib/REPL/src/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -395,15 +395,15 @@ end
# Returns the return type. example: get_type(:(Base.strip("", ' ')), Main) returns (String, true)
function try_get_type(sym::Expr, fn::Module)
val, found = get_value(sym, fn)
found && return Base.typesof(val).parameters[1], found
found && return Core.Typeof(val), found
if sym.head === :call
# getfield call is special cased as the evaluation of getfield provides good type information,
# is inexpensive and it is also performed in the complete_symbol function.
a1 = sym.args[1]
if isa(a1,GlobalRef) && isconst(a1.mod,a1.name) && isdefined(a1.mod,a1.name) &&
eval(a1) === Core.getfield
val, found = get_value_getfield(sym, Main)
return found ? Base.typesof(val).parameters[1] : Any, found
return found ? Core.Typeof(val) : Any, found
end
return get_type_call(sym)
elseif sym.head === :thunk
Expand All @@ -430,7 +430,7 @@ end

function get_type(sym, fn::Module)
val, found = get_value(sym, fn)
return found ? Base.typesof(val).parameters[1] : Any, found
return found ? Core.Typeof(val) : Any, found
end

# Method completion on function call expression that look like :(max(1))
Expand Down
2 changes: 2 additions & 0 deletions test/channels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ end
t = Timer(0) do t
tc[] += 1
end
Libc.systemsleep(0.005)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there something better we can do here. Tests that depend on system scheduling behavior almost always turn out flakey.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this, the test depends on the scheduling (this test assumes that this statement takes a least a millisecond to complete). This completely fixes the test to avoid that flakiness by ensuring it always takes at least that long.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see.

@test isopen(t)
Base.process_events()
@test !isopen(t)
Expand All @@ -402,6 +403,7 @@ end
t = Timer(0) do t
tc[] += 1
end
Libc.systemsleep(0.005)
@test isopen(t)
close(t)
@test !isopen(t)
Expand Down
1 change: 0 additions & 1 deletion test/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,6 @@ f18888() = nothing
let
world = Core.Compiler.get_world_counter()
m = first(methods(f18888, Tuple{}))
@test isempty(m.specializations)
ft = typeof(f18888)

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