diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index 497c9c0252d17..f7ff32ecbaefe 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -127,10 +127,7 @@ function retrieve_code_info(linfo::MethodInstance) end if c === nothing && isdefined(m, :source) src = m.source - if src === nothing - # can happen in images built with --strip-ir - return nothing - elseif isa(src, Array{UInt8,1}) + if isa(src, Array{UInt8,1}) c = ccall(:jl_uncompress_ir, Any, (Any, Ptr{Cvoid}, Any), m, C_NULL, src) else c = copy(src::CodeInfo) diff --git a/src/gf.c b/src/gf.c index f0dcdbb298528..ad84c1c523be8 100644 --- a/src/gf.c +++ b/src/gf.c @@ -281,6 +281,8 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t *mi, size_t world, int force) JL_TIMING(INFERENCE); if (jl_typeinf_func == NULL) return NULL; + if (jl_is_method(mi->def.method) && mi->def.method->unspecialized == mi) + return NULL; // avoid inferring the unspecialized method static int in_inference; if (in_inference > 2) return NULL; @@ -2060,7 +2062,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t if (compile_option == JL_OPTIONS_COMPILE_OFF || compile_option == JL_OPTIONS_COMPILE_MIN) { jl_code_info_t *src = jl_code_for_interpreter(mi); - if (!jl_code_requires_compiler(src, 0)) { + if (!jl_code_requires_compiler(src)) { jl_code_instance_t *codeinst = jl_new_codeinst(mi, (jl_value_t*)jl_any_type, NULL, NULL, 0, 1, ~(size_t)0, 0, 0, jl_nothing, 0); diff --git a/src/julia_internal.h b/src/julia_internal.h index 0906782640406..a7e9c0af2ad3d 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -530,7 +530,7 @@ jl_method_instance_t *jl_get_unspecialized(jl_method_instance_t *method JL_PROPA JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types); jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *lam JL_PROPAGATES_ROOT); -int jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile); +int jl_code_requires_compiler(jl_code_info_t *src); jl_code_info_t *jl_new_code_info_from_ir(jl_expr_t *ast); JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void); void jl_resolve_globals_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, diff --git a/src/precompile.c b/src/precompile.c index d938cbe06bf25..5a43dc45f094e 100644 --- a/src/precompile.c +++ b/src/precompile.c @@ -113,6 +113,13 @@ void jl_write_compiler_output(void) // and expanding the Union may give a leaf function static void _compile_all_tvar_union(jl_value_t *methsig) { + if (!jl_is_unionall(methsig) && jl_is_dispatch_tupletype(methsig)) { + // usually can create a specialized version of the function, + // if the signature is already a dispatch type + if (jl_compile_hint((jl_tupletype_t*)methsig)) + return; + } + int tvarslen = jl_subtype_env_size(methsig); jl_value_t *sigbody = methsig; jl_value_t **roots; @@ -239,49 +246,74 @@ static void _compile_all_union(jl_value_t *sig) JL_GC_POP(); } -static int compile_all_collect__(jl_typemap_entry_t *ml, void *env) +static void _compile_all_deq(jl_array_t *found) +{ + int found_i, found_l = jl_array_len(found); + jl_printf(JL_STDERR, "found %d uncompiled methods for compile-all\n", (int)found_l); + jl_method_instance_t *mi = NULL; + jl_value_t *src = NULL; + JL_GC_PUSH2(&mi, &src); + for (found_i = 0; found_i < found_l; found_i++) { + if (found_i % (1 + found_l / 300) == 0 || found_i == found_l - 1) // show 300 progress steps, to show progress without overwhelming log files + jl_printf(JL_STDERR, " %d / %d\r", found_i + 1, found_l); + jl_typemap_entry_t *ml = (jl_typemap_entry_t*)jl_array_ptr_ref(found, found_i); + jl_method_t *m = ml->func.method; + if (m->source == NULL) // TODO: generic implementations of generated functions + continue; + mi = jl_get_unspecialized(mi); + assert(mi == m->unspecialized); // make sure we didn't get tricked by a generated function, since we can't handle those + jl_code_instance_t *ucache = jl_get_method_inferred(mi, (jl_value_t*)jl_any_type, 1, ~(size_t)0); + if (ucache->invoke != NULL) + continue; + src = m->source; + assert(src); + // TODO: we could now enable storing inferred function pointers in the `unspecialized` cache + //src = jl_type_infer(mi, jl_atomic_load_acquire(&jl_world_counter), 1); + //if (ucache->invoke != NULL) + // continue; + + // first try to create leaf signatures from the signature declaration and compile those + _compile_all_union((jl_value_t*)ml->sig); + // then also compile the generic fallback + jl_generate_fptr_for_unspecialized(ucache); + } + JL_GC_POP(); + jl_printf(JL_STDERR, "\n"); +} + +static int compile_all_enq__(jl_typemap_entry_t *ml, void *env) { - jl_array_t *allmeths = (jl_array_t*)env; + jl_array_t *found = (jl_array_t*)env; + // method definition -- compile template field jl_method_t *m = ml->func.method; if (m->source) { - // method has a non-generated definition; can be compiled generically - jl_array_ptr_1d_push(allmeths, (jl_value_t*)m); + // found a method to compile + jl_array_ptr_1d_push(found, (jl_value_t*)ml); } return 1; } -static int compile_all_collect_(jl_methtable_t *mt, void *env) + +static int compile_all_enq_(jl_methtable_t *mt, void *env) { - jl_typemap_visitor(mt->defs, compile_all_collect__, env); + jl_typemap_visitor(mt->defs, compile_all_enq__, env); return 1; } -static void jl_compile_all_defs(jl_array_t *mis) +static void jl_compile_all_defs(void) { - jl_array_t *allmeths = jl_alloc_vec_any(0); - JL_GC_PUSH1(&allmeths); - - jl_foreach_reachable_mtable(compile_all_collect_, allmeths); - - size_t i, l = jl_array_len(allmeths); - for (i = 0; i < l; i++) { - jl_method_t *m = (jl_method_t*)jl_array_ptr_ref(allmeths, i); - if (jl_isa_compileable_sig((jl_tupletype_t*)m->sig, m)) { - // method has a single compileable specialization, e.g. its definition - // signature is concrete. in this case we can just hint it. - jl_compile_hint((jl_tupletype_t*)m->sig); - } - else { - // first try to create leaf signatures from the signature declaration and compile those - _compile_all_union(m->sig); - - // finally, compile a fully generic fallback that can work for all arguments - jl_method_instance_t *unspec = jl_get_unspecialized(m); - if (unspec) - jl_array_ptr_1d_push(mis, (jl_value_t*)unspec); - } + // this "found" array will contain + // TypeMapEntries for Methods and MethodInstances that need to be compiled + jl_array_t *m = jl_alloc_vec_any(0); + JL_GC_PUSH1(&m); + while (1) { + jl_foreach_reachable_mtable(compile_all_enq_, m); + size_t changes = jl_array_len(m); + if (!changes) + break; + _compile_all_deq(m); + jl_array_del_end(m, changes); } - JL_GC_POP(); } @@ -339,13 +371,14 @@ static int precompile_enq_all_specializations_(jl_methtable_t *mt, void *env) static void *jl_precompile(int all) { - // array of MethodInstances and ccallable aliases to include in the output + if (all) + jl_compile_all_defs(); + // this "found" array will contain function + // type signatures that were inferred but haven't been compiled jl_array_t *m = jl_alloc_vec_any(0); jl_array_t *m2 = NULL; jl_method_instance_t *mi = NULL; JL_GC_PUSH3(&m, &m2, &mi); - if (all) - jl_compile_all_defs(m); jl_foreach_reachable_mtable(precompile_enq_all_specializations_, m); m2 = jl_alloc_vec_any(0); for (size_t i = 0; i < jl_array_len(m); i++) { @@ -354,7 +387,7 @@ static void *jl_precompile(int all) mi = (jl_method_instance_t*)item; size_t min_world = 0; size_t max_world = ~(size_t)0; - if (mi != jl_atomic_load_relaxed(&mi->def.method->unspecialized) && !jl_isa_compileable_sig((jl_tupletype_t*)mi->specTypes, mi->def.method)) + if (!jl_isa_compileable_sig((jl_tupletype_t*)mi->specTypes, mi->def.method)) mi = jl_get_specialization1((jl_tupletype_t*)mi->specTypes, jl_atomic_load_acquire(&jl_world_counter), &min_world, &max_world, 0); if (mi) jl_array_ptr_1d_push(m2, (jl_value_t*)mi); diff --git a/src/toplevel.c b/src/toplevel.c index 5d703e3d183bb..1f60a1b57c19c 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -337,7 +337,7 @@ JL_DLLEXPORT jl_module_t *jl_base_relative_to(jl_module_t *m) return jl_top_module; } -static void expr_attributes(jl_value_t *v, int *has_ccall, int *has_defs, int *has_opaque) +static void expr_attributes(jl_value_t *v, int *has_intrinsics, int *has_defs, int *has_opaque) { if (!jl_is_expr(v)) return; @@ -361,11 +361,11 @@ static void expr_attributes(jl_value_t *v, int *has_ccall, int *has_defs, int *h *has_defs = 1; } else if (head == jl_cfunction_sym) { - *has_ccall = 1; + *has_intrinsics = 1; return; } else if (head == jl_foreigncall_sym) { - *has_ccall = 1; + *has_intrinsics = 1; return; } else if (head == jl_new_opaque_closure_sym) { @@ -389,7 +389,7 @@ static void expr_attributes(jl_value_t *v, int *has_ccall, int *has_defs, int *h } if (called) { if (jl_is_intrinsic(called) && jl_unbox_int32(called) == (int)llvmcall) { - *has_ccall = 1; + *has_intrinsics = 1; } if (called == jl_builtin__typebody) { *has_defs = 1; @@ -401,28 +401,28 @@ static void expr_attributes(jl_value_t *v, int *has_ccall, int *has_defs, int *h for (i = 0; i < jl_array_len(e->args); i++) { jl_value_t *a = jl_exprarg(e, i); if (jl_is_expr(a)) - expr_attributes(a, has_ccall, has_defs, has_opaque); + expr_attributes(a, has_intrinsics, has_defs, has_opaque); } } -int jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile) +int jl_code_requires_compiler(jl_code_info_t *src) { jl_array_t *body = src->code; assert(jl_typeis(body, jl_array_any_type)); size_t i; - int has_ccall = 0, has_defs = 0, has_opaque = 0; - if (include_force_compile && jl_has_meta(body, jl_force_compile_sym)) + int has_intrinsics = 0, has_defs = 0, has_opaque = 0; + if (jl_has_meta(body, jl_force_compile_sym)) return 1; for(i=0; i < jl_array_len(body); i++) { jl_value_t *stmt = jl_array_ptr_ref(body,i); - expr_attributes(stmt, &has_ccall, &has_defs, &has_opaque); - if (has_ccall) + expr_attributes(stmt, &has_intrinsics, &has_defs, &has_opaque); + if (has_intrinsics) return 1; } return 0; } -static void body_attributes(jl_array_t *body, int *has_ccall, int *has_defs, int *has_loops, int *has_opaque, int *forced_compile) +static void body_attributes(jl_array_t *body, int *has_intrinsics, int *has_defs, int *has_loops, int *has_opaque, int *forced_compile) { size_t i; *has_loops = 0; @@ -438,7 +438,7 @@ static void body_attributes(jl_array_t *body, int *has_ccall, int *has_defs, int *has_loops = 1; } } - expr_attributes(stmt, has_ccall, has_defs, has_opaque); + expr_attributes(stmt, has_intrinsics, has_defs, has_opaque); } *forced_compile = jl_has_meta(body, jl_force_compile_sym); } @@ -868,16 +868,16 @@ jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_value_t *e, int return (jl_value_t*)ex; } - int has_ccall = 0, has_defs = 0, has_loops = 0, has_opaque = 0, forced_compile = 0; + int has_intrinsics = 0, has_defs = 0, has_loops = 0, has_opaque = 0, forced_compile = 0; assert(head == jl_thunk_sym); thk = (jl_code_info_t*)jl_exprarg(ex, 0); assert(jl_is_code_info(thk)); assert(jl_typeis(thk->code, jl_array_any_type)); - body_attributes((jl_array_t*)thk->code, &has_ccall, &has_defs, &has_loops, &has_opaque, &forced_compile); + body_attributes((jl_array_t*)thk->code, &has_intrinsics, &has_defs, &has_loops, &has_opaque, &forced_compile); jl_value_t *result; - if (has_ccall || - ((forced_compile || (!has_defs && fast && has_loops)) && + if (forced_compile || has_intrinsics || + (!has_defs && fast && has_loops && jl_options.compile_enabled != JL_OPTIONS_COMPILE_OFF && jl_options.compile_enabled != JL_OPTIONS_COMPILE_MIN && jl_get_module_compile(m) != JL_OPTIONS_COMPILE_OFF &&