diff --git a/src/dump.c b/src/dump.c index 0c279b43d1c19..9d4ea3108d05c 100644 --- a/src/dump.c +++ b/src/dump.c @@ -246,12 +246,47 @@ static int type_recursively_external(jl_datatype_t *dt) JL_NOTSAFEPOINT return 1; } +// When we infer external method instances, ensure they link back to the +// package. Otherwise they might be, e.g., for external macros +static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited) +{ + void **bp = ptrhash_bp(visited, mi); + // HT_NOTFOUND: not yet analyzed + // HT_NOTFOUND + 1: doesn't link back + // HT_NOTFOUND + 2: does link back + if (*bp != HT_NOTFOUND) + return (char*)*bp - (char*)HT_NOTFOUND - 1; + *bp = (void*)((char*)HT_NOTFOUND + 1); // preliminarily mark as "not found" + jl_module_t *mod = mi->def.module; + if (jl_is_method(mod)) + mod = ((jl_method_t*)mod)->module; + assert(jl_is_module(mod)); + if (mi->precompiled || module_in_worklist(mod)) { + *bp = (void*)((char*)HT_NOTFOUND + 2); // found + return 1; + } + if (!mi->backedges) { + return 0; + } + size_t i, n = jl_array_len(mi->backedges); + for (i = 0; i < n; i++) { + jl_method_instance_t *be = (jl_method_instance_t*)jl_array_ptr_ref(mi->backedges, i); + if (has_backedge_to_worklist(be, visited)) { + *bp = (void*)((char*)HT_NOTFOUND + 2); // found + return 1; + } + } + return 0; +} + // given the list of MethodInstances that were inferred during the // build, select those that are external and have at least one // relocatable CodeInstance. static size_t queue_external_mis(jl_array_t *list) { size_t i, n = 0; + htable_t visited; + htable_new(&visited, 0); if (list) { assert(jl_is_array(list)); size_t n0 = jl_array_len(list); @@ -268,13 +303,16 @@ static size_t queue_external_mis(jl_array_t *list) ci = ci->next; } if (relocatable && ptrhash_get(&external_mis, mi) == HT_NOTFOUND) { - ptrhash_put(&external_mis, mi, mi); - n++; + if (has_backedge_to_worklist(mi, &visited)) { + ptrhash_put(&external_mis, mi, mi); + n++; + } } } } } } + htable_free(&visited); return n; } diff --git a/src/gf.c b/src/gf.c index 101c2bd952708..91d51f643b7dd 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2248,6 +2248,7 @@ JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) if (mi == NULL) return 0; JL_GC_PROMISE_ROOTED(mi); + mi->precompiled = 1; if (jl_generating_output()) { jl_compile_now(mi); // In addition to full compilation of the compilation-signature, if `types` is more specific (e.g. due to nospecialize), @@ -2262,6 +2263,7 @@ JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) types2 = jl_type_intersection_env((jl_value_t*)types, (jl_value_t*)mi->def.method->sig, &tpenv2); jl_method_instance_t *li2 = jl_specializations_get_linfo(mi->def.method, (jl_value_t*)types2, tpenv2); JL_GC_POP(); + li2->precompiled = 1; if (jl_rettype_inferred(li2, world, world) == jl_nothing) (void)jl_type_infer(li2, world, 1); if (jl_typeinf_func && mi->def.method->primary_world <= tworld) { diff --git a/src/jltypes.c b/src/jltypes.c index cb9141dd50fd4..a24e9f7e488bd 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2466,7 +2466,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_method_instance_type = jl_new_datatype(jl_symbol("MethodInstance"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(8, + jl_perm_symsvec(9, "def", "specTypes", "sparam_vals", @@ -2474,8 +2474,9 @@ void jl_init_types(void) JL_GC_DISABLED "backedges", "callbacks", "cache", - "inInference"), - jl_svec(8, + "inInference", + "precompiled"), + jl_svec(9, jl_new_struct(jl_uniontype_type, jl_method_type, jl_module_type), jl_any_type, jl_simplevector_type, @@ -2483,6 +2484,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type, jl_any_type, jl_any_type, + jl_bool_type, jl_bool_type), jl_emptysvec, 0, 1, 3); diff --git a/src/julia.h b/src/julia.h index fbaef8d963007..afb0d00630dbd 100644 --- a/src/julia.h +++ b/src/julia.h @@ -361,6 +361,7 @@ struct _jl_method_instance_t { jl_array_t *callbacks; // list of callback functions to inform external caches about invalidations _Atomic(struct _jl_code_instance_t*) cache; uint8_t inInference; // flags to tell if inference is running on this object + uint8_t precompiled; // true if this instance was generated by an explicit `precompile(...)` call }; // OpaqueClosure diff --git a/src/method.c b/src/method.c index e8a8c6e763d9b..7325670bd76a4 100644 --- a/src/method.c +++ b/src/method.c @@ -439,6 +439,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_new_method_instance_uninit(void) li->callbacks = NULL; jl_atomic_store_relaxed(&li->cache, NULL); li->inInference = 0; + li->precompiled = 0; return li; }