diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index f7ff32ecbaefe..497c9c0252d17 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -127,7 +127,10 @@ function retrieve_code_info(linfo::MethodInstance) end if c === nothing && isdefined(m, :source) src = m.source - if isa(src, Array{UInt8,1}) + if src === nothing + # can happen in images built with --strip-ir + return nothing + elseif 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 ad84c1c523be8..f0dcdbb298528 100644 --- a/src/gf.c +++ b/src/gf.c @@ -281,8 +281,6 @@ 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; @@ -2062,7 +2060,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)) { + if (!jl_code_requires_compiler(src, 0)) { 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 a7e9c0af2ad3d..0906782640406 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 jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile); 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 5a43dc45f094e..d938cbe06bf25 100644 --- a/src/precompile.c +++ b/src/precompile.c @@ -113,13 +113,6 @@ 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; @@ -246,74 +239,49 @@ static void _compile_all_union(jl_value_t *sig) JL_GC_POP(); } -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) +static int compile_all_collect__(jl_typemap_entry_t *ml, void *env) { - jl_array_t *found = (jl_array_t*)env; - // method definition -- compile template field + jl_array_t *allmeths = (jl_array_t*)env; jl_method_t *m = ml->func.method; if (m->source) { - // found a method to compile - jl_array_ptr_1d_push(found, (jl_value_t*)ml); + // method has a non-generated definition; can be compiled generically + jl_array_ptr_1d_push(allmeths, (jl_value_t*)m); } return 1; } - -static int compile_all_enq_(jl_methtable_t *mt, void *env) +static int compile_all_collect_(jl_methtable_t *mt, void *env) { - jl_typemap_visitor(mt->defs, compile_all_enq__, env); + jl_typemap_visitor(mt->defs, compile_all_collect__, env); return 1; } -static void jl_compile_all_defs(void) +static void jl_compile_all_defs(jl_array_t *mis) { - // 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_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); + } } + JL_GC_POP(); } @@ -371,14 +339,13 @@ static int precompile_enq_all_specializations_(jl_methtable_t *mt, void *env) static void *jl_precompile(int all) { - if (all) - jl_compile_all_defs(); - // this "found" array will contain function - // type signatures that were inferred but haven't been compiled + // array of MethodInstances and ccallable aliases to include in the output 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++) { @@ -387,7 +354,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 (!jl_isa_compileable_sig((jl_tupletype_t*)mi->specTypes, mi->def.method)) + if (mi != jl_atomic_load_relaxed(&mi->def.method->unspecialized) && !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 1f60a1b57c19c..5d703e3d183bb 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_intrinsics, int *has_defs, int *has_opaque) +static void expr_attributes(jl_value_t *v, int *has_ccall, 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_intrinsics, int *has_defs, i *has_defs = 1; } else if (head == jl_cfunction_sym) { - *has_intrinsics = 1; + *has_ccall = 1; return; } else if (head == jl_foreigncall_sym) { - *has_intrinsics = 1; + *has_ccall = 1; return; } else if (head == jl_new_opaque_closure_sym) { @@ -389,7 +389,7 @@ static void expr_attributes(jl_value_t *v, int *has_intrinsics, int *has_defs, i } if (called) { if (jl_is_intrinsic(called) && jl_unbox_int32(called) == (int)llvmcall) { - *has_intrinsics = 1; + *has_ccall = 1; } if (called == jl_builtin__typebody) { *has_defs = 1; @@ -401,28 +401,28 @@ static void expr_attributes(jl_value_t *v, int *has_intrinsics, int *has_defs, i 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_intrinsics, has_defs, has_opaque); + expr_attributes(a, has_ccall, has_defs, has_opaque); } } -int jl_code_requires_compiler(jl_code_info_t *src) +int jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile) { jl_array_t *body = src->code; assert(jl_typeis(body, jl_array_any_type)); size_t i; - int has_intrinsics = 0, has_defs = 0, has_opaque = 0; - if (jl_has_meta(body, jl_force_compile_sym)) + int has_ccall = 0, has_defs = 0, has_opaque = 0; + if (include_force_compile && 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_intrinsics, &has_defs, &has_opaque); - if (has_intrinsics) + expr_attributes(stmt, &has_ccall, &has_defs, &has_opaque); + if (has_ccall) return 1; } return 0; } -static void body_attributes(jl_array_t *body, int *has_intrinsics, int *has_defs, int *has_loops, int *has_opaque, int *forced_compile) +static void body_attributes(jl_array_t *body, int *has_ccall, 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_intrinsics, int *has_defs *has_loops = 1; } } - expr_attributes(stmt, has_intrinsics, has_defs, has_opaque); + expr_attributes(stmt, has_ccall, 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_intrinsics = 0, has_defs = 0, has_loops = 0, has_opaque = 0, forced_compile = 0; + int has_ccall = 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_intrinsics, &has_defs, &has_loops, &has_opaque, &forced_compile); + body_attributes((jl_array_t*)thk->code, &has_ccall, &has_defs, &has_loops, &has_opaque, &forced_compile); jl_value_t *result; - if (forced_compile || has_intrinsics || - (!has_defs && fast && has_loops && + if (has_ccall || + ((forced_compile || (!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 &&