From b16d315dddf4c3fe9e30d7fe804988ea01c34c06 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 26 Feb 2017 19:15:32 -0500 Subject: [PATCH] reorg: move code related to static compilation to compileout.c --- src/Makefile | 2 +- src/compileout.c | 442 +++++++++++++++++++++++++++++++++++++++++++++++ src/gf.c | 374 +-------------------------------------- src/init.c | 72 +------- 4 files changed, 454 insertions(+), 436 deletions(-) create mode 100644 src/compileout.c diff --git a/src/Makefile b/src/Makefile index 4dab3bfa2a3346..3e2adf5c5c228e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -42,7 +42,7 @@ endif SRCS := \ jltypes gf typemap ast builtins module interpreter symbol \ dlload sys init task array dump toplevel jl_uv datatype \ - simplevector APInt-C runtime_intrinsics runtime_ccall \ + simplevector APInt-C runtime_intrinsics runtime_ccall compileout \ threadgroup threading stackwalk gc gc-debug gc-pages method \ jlapi signal-handling safepoint jloptions timing subtype rtutils diff --git a/src/compileout.c b/src/compileout.c new file mode 100644 index 00000000000000..21e247b1563f68 --- /dev/null +++ b/src/compileout.c @@ -0,0 +1,442 @@ +// This file is a part of Julia. License is MIT: http://julialang.org/license + +/* + compileout.c + Generating compiler output artifacts (object files, etc.) +*/ + +#include +#include + +#include "julia.h" +#include "julia_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +JL_DLLEXPORT int jl_generating_output(void) +{ + return jl_options.outputo || jl_options.outputbc || jl_options.outputji; +} + +void jl_precompile(int all); + +void jl_write_compiler_output(void) +{ + if (!jl_generating_output()) + return; + + if (!jl_options.incremental) + jl_precompile(jl_options.compile_enabled == JL_OPTIONS_COMPILE_ALL); + + if (!jl_module_init_order) { + jl_printf(JL_STDERR, "WARNING: --output requested, but no modules defined during run\n"); + return; + } + + jl_array_t *worklist = jl_module_init_order; + JL_GC_PUSH1(&worklist); + jl_module_init_order = jl_alloc_vec_any(0); + int i, l = jl_array_len(worklist); + for (i = 0; i < l; i++) { + jl_value_t *m = jl_arrayref(worklist, i); + if (jl_get_global((jl_module_t*)m, jl_symbol("__init__"))) { + jl_array_ptr_1d_push(jl_module_init_order, m); + } + } + + if (jl_options.incremental) { + if (jl_options.outputji) + if (jl_save_incremental(jl_options.outputji, worklist)) + jl_exit(1); + if (jl_options.outputbc) + jl_printf(JL_STDERR, "WARNING: incremental output to a .bc file is not implemented\n"); + if (jl_options.outputo) + jl_printf(JL_STDERR, "WARNING: incremental output to a .o file is not implemented\n"); + } + else { + ios_t *s = NULL; + if (jl_options.outputo || jl_options.outputbc) + s = jl_create_system_image(); + + if (jl_options.outputji) { + if (s == NULL) { + jl_save_system_image(jl_options.outputji); + } + else { + ios_t f; + if (ios_file(&f, jl_options.outputji, 1, 1, 1, 1) == NULL) + jl_errorf("cannot open system image file \"%s\" for writing", jl_options.outputji); + ios_write(&f, (const char*)s->buf, (size_t)s->size); + ios_close(&f); + } + } + + if (jl_options.outputo || jl_options.outputbc) + jl_dump_native(jl_options.outputbc, + jl_options.outputo, + (const char*)s->buf, (size_t)s->size); + } + JL_GC_POP(); +} + +int jl_is_rettype_inferred(jl_method_instance_t *li); + +JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) +{ + size_t world = jl_world_counter; + jl_method_instance_t *li = jl_get_specialization1(types, world); + if (li == NULL) + return 0; + jl_code_info_t *src = NULL; + if (!jl_is_rettype_inferred(li)) + src = jl_type_infer(&li, world, 0); + if (li->jlcall_api != 2) + jl_compile_linfo(&li, src, world, &jl_default_cgparams); + return 1; +} + +#if 0 // TODO restore this for jb/subtype +static int tupletype_any_bottom(jl_value_t *sig) +{ + sig = jl_unwrap_unionall(sig); + assert(jl_is_tuple_type(sig)); + jl_svec_t *types = ((jl_tupletype_t*)sig)->types; + size_t i, l = jl_svec_len(types); + for (i = 0; i < l; i++) { + if (jl_svecref(types, i) == jl_bottom_type) + return 1; + } + return 0; +} + +static int _compile_all_tvar_union(jl_tupletype_t *methsig, jl_svec_t *tvars) +{ + // f{<:Union{...}}(...) is a common pattern + // and expanding the Union may give a leaf function + jl_tvar_t **tvs; + int tvarslen; + if (jl_is_typevar(tvars)) { + tvs = (jl_tvar_t**)&tvars; + tvarslen = 1; + } + else { + tvs = (jl_tvar_t**)jl_svec_data(tvars); + tvarslen = jl_svec_len(tvars); + if (tvarslen == 0) { + if (jl_is_leaf_type((jl_value_t*)methsig)) { + // usually can create a specialized version of the function, + // if the signature is already a leaftype + if (jl_compile_hint(methsig)) { + return 1; + } + } + return 0; + } + } + + int complete = 1; + jl_value_t **env; + JL_GC_PUSHARGS(env, 2 * tvarslen); + int *idx = (int*)alloca(sizeof(int) * tvarslen); + int i; + for (i = 0; i < tvarslen; i++) { + idx[i] = 0; + env[2 * i] = (jl_value_t*)tvs[i]; + env[2 * i + 1] = jl_bottom_type; // initialize the list with Union{}, since T<:Union{} is always a valid option + } + + for (i = 0; i < tvarslen; /* incremented by inner loop */) { + jl_value_t *sig; + JL_TRY { + sig = (jl_value_t*) + jl_instantiate_type_with((jl_value_t*)methsig, env, tvarslen); + } + JL_CATCH { + goto getnext; // sigh, we found an invalid type signature. should we warn the user? + } + assert(jl_is_tuple_type(sig)); + if (sig == jl_bottom_type || tupletype_any_bottom(sig)) { + goto getnext; // signature wouldn't be callable / is invalid -- skip it + } + if (jl_is_leaf_type(sig)) { + if (jl_compile_hint((jl_tupletype_t*)sig)) { + if (!jl_has_typevars((jl_value_t*)sig)) goto getnext; // success + } + } + complete = 0; + +getnext: + for (i = 0; i < tvarslen; i++) { + jl_tvar_t *tv = tvs[i]; + if (jl_is_uniontype(tv->ub)) { + jl_uniontype_t *ub = (jl_uniontype_t*)tv->ub; + size_t l = jl_svec_len(ub->types); + size_t j = idx[i]; + if (j == l) { + env[2 * i + 1] = jl_bottom_type; + idx[i] = 0; + } + else { + jl_value_t *ty = jl_svecref(ub->types, j); + if (!jl_is_leaf_type(ty)) + ty = (jl_value_t*)jl_new_typevar(tv->name, tv->lb, ty); + env[2 * i + 1] = ty; + idx[i] = j + 1; + break; + } + } + else { + env[2 * i + 1] = (jl_value_t*)tv; + complete = 0; + } + } + } + JL_GC_POP(); + return complete; +} +#endif +#if 0 +static int _compile_all_union(jl_tupletype_t *sig, jl_svec_t *tvars) +{ + // f(::Union{...}, ...) is a common pattern + // and expanding the Union may give a leaf function + int complete = 1; + size_t count_unions = 0; + size_t i, l = jl_svec_len(sig->parameters); + jl_svec_t *p = NULL; + jl_tupletype_t *methsig = NULL; + + for (i = 0; i < l; i++) { + jl_value_t *ty = jl_svecref(sig->parameters, i); + if (jl_is_uniontype(ty)) { + jl_svec_t *utypes = ((jl_uniontype_t*)ty)->types; + size_t l = jl_svec_len(utypes); + if (l == 0) + return 1; // why does this method exist? + ++count_unions; + } + } + + //if (count_unions == 0) + // return _compile_all_tvar_union(sig, tvars); + + int *idx = (int*)alloca(sizeof(int) * count_unions); + for (i = 0; i < count_unions; i++) { + idx[i] = 0; + } + + JL_GC_PUSH2(&p, &methsig); + int idx_ctr = 0, incr = 0; + while (!incr) { + jl_svec_t *p = jl_alloc_svec_uninit(l); + for (i = 0, idx_ctr = 0, incr = 1; i < l; i++) { + jl_value_t *ty = jl_svecref(sig->parameters, i); + if (jl_is_uniontype(ty)) { + jl_svec_t *utypes = ((jl_uniontype_t*)ty)->types; + size_t l = jl_svec_len(utypes); + size_t j = idx[idx_ctr]; + jl_svecset(p, i, jl_svecref(utypes, j)); + ++j; + if (incr) { + if (j == l) { + idx[idx_ctr] = 0; + } + else { + idx[idx_ctr] = j; + incr = 0; + } + } + ++idx_ctr; + } + else { + jl_svecset(p, i, ty); + } + } + methsig = jl_apply_tuple_type(p); + //if (!_compile_all_tvar_union(methsig, tvars)) + // complete = 0; + } + + JL_GC_POP(); + return complete; +} +#endif + +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 *linfo = NULL; + jl_code_info_t *src = NULL; + JL_GC_PUSH2(&linfo, &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; + jl_method_instance_t *linfo = m->unspecialized; + if (!linfo) { + linfo = jl_get_specialized(m, (jl_value_t*)ml->sig, jl_emptysvec); + m->unspecialized = linfo; + jl_gc_wb(m, linfo); + } + + //// infer this function now, if necessary + //if (linfo->jlcall_api == 2) + // continue; + //src = jl_type_infer(&linfo, jl_world_counter, 1); + //if (linfo->jlcall_api == 2) + // continue; + + // keep track of whether all possible signatures have been cached (and thus whether it can skip trying to compile the template function) + // this is necessary because many intrinsics try to call static_eval and thus are not compilable unspecialized + int complete = 0;//_compile_all_union(ml->sig, ml->tvars); + if (complete) { + if (linfo->fptr == NULL && linfo->functionObjectsDecls.functionObject == NULL) + // indicate that this method doesn't need to be compiled, because it was fully covered above + // TODO: do this some other way + linfo->fptr = (jl_fptr_t)(uintptr_t)-1; + } + else { + jl_compile_linfo(&linfo, src, jl_world_counter, &jl_default_cgparams); + assert(linfo->functionObjectsDecls.functionObject != NULL); + } + } + JL_GC_POP(); + jl_printf(JL_STDERR, "\n"); +} + +static int _compile_all_enq(jl_typemap_entry_t *ml, void *env) +{ + jl_array_t *found = (jl_array_t*)env; + // method definition -- compile template field + jl_method_t *m = ml->func.method; + if (!m->unspecialized || + (m->unspecialized->functionObjectsDecls.functionObject == NULL && + m->unspecialized->jlcall_api != 2 && + m->unspecialized->fptr == NULL)) { + // found a lambda that still needs to be compiled + jl_array_ptr_1d_push(found, (jl_value_t*)ml); + } + return 1; +} + +static void _compile_all_enq_module(jl_module_t *m, jl_array_t *found) +{ + // scan through all types reachable from 'v' and + // record all jl_method_instance_t objects and signatures in their method tables + size_t i, sz = m->bindings.size; + for(i=1; i < sz; i+=2) { + if (m->bindings.table[i] != HT_NOTFOUND) { + jl_binding_t *b = (jl_binding_t*)m->bindings.table[i]; + if (b->owner == m && b->value && b->constp) { + jl_value_t *v = b->value; + if (jl_is_datatype(v)) { + jl_typename_t *tn = ((jl_datatype_t*)v)->name; + if (tn->module == m && tn->name == b->name) { + jl_methtable_t *mt = tn->mt; + if (mt != NULL && (jl_value_t*)mt != jl_nothing) { + jl_typemap_visitor(mt->defs, _compile_all_enq, (void*)found); + } + } + } + else if (jl_is_module(v)) { + jl_module_t *child = (jl_module_t*)b->value; + if (child != m && child->parent == m && child->name == b->name) { + // this is the original/primary binding for the submodule + _compile_all_enq_module(child, found); + } + } + } + } + } +} + +static void jl_compile_all_defs(void) +{ + // 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) { + _compile_all_enq_module(jl_main_module, m); + size_t changes = jl_array_len(m); + if (!changes) + break; + _compile_all_deq(m); + jl_array_del_end(m, changes); + } + JL_GC_POP(); +} + +static int _precompile_enq_tfunc(jl_typemap_entry_t *l, void *closure) +{ + if (jl_is_method_instance(l->func.value) && + l->func.linfo->functionObjectsDecls.functionObject == NULL && + l->func.linfo->jlcall_api != 2) + jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)l->sig); + return 1; +} + +static int _precompile_enq_spec(jl_typemap_entry_t *def, void *closure) +{ + jl_typemap_visitor(def->func.method->specializations, _precompile_enq_tfunc, closure); + return 1; +} + +static void _precompile_enq_module(jl_module_t *m, jl_array_t *unspec) +{ + // removes all method caches + size_t i; + void **table = m->bindings.table; + for (i = 1; i < m->bindings.size; i += 2) { + if (table[i] != HT_NOTFOUND) { + jl_binding_t *b = (jl_binding_t*)table[i]; + if (b->owner == m && b->value && b->constp) { + if (jl_is_datatype(b->value)) { + jl_typename_t *tn = ((jl_datatype_t*)b->value)->name; + if (tn->module == m && tn->name == b->name) { + jl_methtable_t *mt = tn->mt; + if (mt != NULL && (jl_value_t*)mt != jl_nothing) { + jl_typemap_visitor(mt->defs, _precompile_enq_spec, (void*)unspec); + } + } + } + else if (jl_is_module(b->value)) { + jl_module_t *child = (jl_module_t*)b->value; + if (child != m && child->parent == m && child->name == b->name) { + // this is the original/primary binding for the submodule + _precompile_enq_module((jl_module_t*)b->value, unspec); + } + } + } + } + } +} + +static void jl_compile_specializations(void) +{ + // 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_GC_PUSH1(&m); + _precompile_enq_module(jl_main_module, m); + size_t i, l; + for (i = 0, l = jl_array_len(m); i < l; i++) { + jl_compile_hint((jl_tupletype_t*)jl_array_ptr_ref(m, i)); + } + JL_GC_POP(); +} + +void jl_precompile(int all) +{ + if (all) + jl_compile_all_defs(); + jl_compile_specializations(); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/gf.c b/src/gf.c index 79b6ea7ca75678..db9aa0d4a25d2f 100644 --- a/src/gf.c +++ b/src/gf.c @@ -3,10 +3,10 @@ /* Generic Functions . method table and lookup - . GF constructor, add_method + . GF constructor . dispatch . static parameter inference - . method specialization, invoking type inference + . method specialization and caching, invoking type inference */ #include #include @@ -280,8 +280,7 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t **pli, size_t world, int forc return src; } - -static int jl_is_rettype_inferred(jl_method_instance_t *li) +int jl_is_rettype_inferred(jl_method_instance_t *li) { if (!li->inferred) return 0; @@ -290,11 +289,11 @@ static int jl_is_rettype_inferred(jl_method_instance_t *li) return 1; } - struct set_world { jl_method_instance_t *replaced; size_t world; }; + static int set_max_world2(jl_typemap_entry_t *entry, void *closure0) { struct set_world *closure = (struct set_world*)closure0; @@ -304,6 +303,7 @@ static int set_max_world2(jl_typemap_entry_t *entry, void *closure0) } return 1; } + static int set_min_world2(jl_typemap_entry_t *entry, void *closure0) { struct set_world *closure = (struct set_world*)closure0; @@ -313,6 +313,7 @@ static int set_min_world2(jl_typemap_entry_t *entry, void *closure0) } return 1; } + static void update_world_bound(jl_method_instance_t *replaced, jl_typemap_visitor_fptr fptr, size_t world) { struct set_world update; @@ -331,7 +332,6 @@ static void update_world_bound(jl_method_instance_t *replaced, jl_typemap_visito jl_typemap_visitor(gf->name->mt->cache, fptr, (void*)&update); } - JL_DLLEXPORT jl_method_instance_t* jl_set_method_inferred( jl_method_instance_t *li, jl_value_t *rettype, jl_value_t *inferred_const, jl_value_t *inferred, @@ -425,7 +425,6 @@ JL_DLLEXPORT jl_method_instance_t* jl_set_method_inferred( return li; } - static int get_spec_unspec_list(jl_typemap_entry_t *l, void *closure) { if (jl_is_method_instance(l->func.value) && !jl_is_rettype_inferred(l->func.linfo)) @@ -439,7 +438,6 @@ static int get_method_unspec_list(jl_typemap_entry_t *def, void *closure) return 1; } - static void jl_reset_mt_caches(jl_module_t *m, jl_array_t *unspec) { // removes all method caches @@ -1155,8 +1153,7 @@ static int check_ambiguous_visitor(jl_typemap_entry_t *oldentry, struct typemap_ return 1; } -static jl_value_t *check_ambiguous_matches(union jl_typemap_t defs, - jl_typemap_entry_t *newentry) +static jl_value_t *check_ambiguous_matches(union jl_typemap_t defs, jl_typemap_entry_t *newentry) { jl_tupletype_t *type = newentry->sig; jl_tupletype_t *ttypes = (jl_tupletype_t*)jl_unwrap_unionall((jl_value_t*)type); @@ -1216,7 +1213,6 @@ static void update_max_args(jl_methtable_t *mt, jl_value_t *type) mt->max_args = na; } - // invalidate cached methods that had an edge to a replaced method static void invalidate_method_instance(jl_method_instance_t *replaced, size_t max_world) { @@ -1655,20 +1651,6 @@ jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types, size_t world return sf; } -JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) -{ - size_t world = jl_world_counter; - jl_method_instance_t *li = jl_get_specialization1(types, world); - if (li == NULL) - return 0; - jl_code_info_t *src = NULL; - if (!jl_is_rettype_inferred(li)) - src = jl_type_infer(&li, world, 0); - if (li->jlcall_api != 2) - jl_compile_linfo(&li, src, world, &jl_default_cgparams); - return 1; -} - JL_DLLEXPORT jl_value_t *jl_get_spec_lambda(jl_tupletype_t *types, size_t world) { jl_method_instance_t *li = jl_get_specialization1(types, world); @@ -1706,345 +1688,6 @@ jl_tupletype_t *jl_argtype_with_function(jl_function_t *f, jl_tupletype_t *types return (jl_tupletype_t*)tt; } -#if 0 // TODO restore this for jb/subtype -static int tupletype_any_bottom(jl_value_t *sig) -{ - sig = jl_unwrap_unionall(sig); - assert(jl_is_tuple_type(sig)); - jl_svec_t *types = ((jl_tupletype_t*)sig)->types; - size_t i, l = jl_svec_len(types); - for (i = 0; i < l; i++) { - if (jl_svecref(types, i) == jl_bottom_type) - return 1; - } - return 0; -} - -static int _compile_all_tvar_union(jl_tupletype_t *methsig, jl_svec_t *tvars) -{ - // f{<:Union{...}}(...) is a common pattern - // and expanding the Union may give a leaf function - jl_tvar_t **tvs; - int tvarslen; - if (jl_is_typevar(tvars)) { - tvs = (jl_tvar_t**)&tvars; - tvarslen = 1; - } - else { - tvs = (jl_tvar_t**)jl_svec_data(tvars); - tvarslen = jl_svec_len(tvars); - if (tvarslen == 0) { - if (jl_is_leaf_type((jl_value_t*)methsig)) { - // usually can create a specialized version of the function, - // if the signature is already a leaftype - if (jl_compile_hint(methsig)) { - return 1; - } - } - return 0; - } - } - - int complete = 1; - jl_value_t **env; - JL_GC_PUSHARGS(env, 2 * tvarslen); - int *idx = (int*)alloca(sizeof(int) * tvarslen); - int i; - for (i = 0; i < tvarslen; i++) { - idx[i] = 0; - env[2 * i] = (jl_value_t*)tvs[i]; - env[2 * i + 1] = jl_bottom_type; // initialize the list with Union{}, since T<:Union{} is always a valid option - } - - for (i = 0; i < tvarslen; /* incremented by inner loop */) { - jl_value_t *sig; - JL_TRY { - sig = (jl_value_t*) - jl_instantiate_type_with((jl_value_t*)methsig, env, tvarslen); - } - JL_CATCH { - goto getnext; // sigh, we found an invalid type signature. should we warn the user? - } - assert(jl_is_tuple_type(sig)); - if (sig == jl_bottom_type || tupletype_any_bottom(sig)) { - goto getnext; // signature wouldn't be callable / is invalid -- skip it - } - if (jl_is_leaf_type(sig)) { - if (jl_compile_hint((jl_tupletype_t*)sig)) { - if (!jl_has_typevars((jl_value_t*)sig)) goto getnext; // success - } - } - complete = 0; - -getnext: - for (i = 0; i < tvarslen; i++) { - jl_tvar_t *tv = tvs[i]; - if (jl_is_uniontype(tv->ub)) { - jl_uniontype_t *ub = (jl_uniontype_t*)tv->ub; - size_t l = jl_svec_len(ub->types); - size_t j = idx[i]; - if (j == l) { - env[2 * i + 1] = jl_bottom_type; - idx[i] = 0; - } - else { - jl_value_t *ty = jl_svecref(ub->types, j); - if (!jl_is_leaf_type(ty)) - ty = (jl_value_t*)jl_new_typevar(tv->name, tv->lb, ty); - env[2 * i + 1] = ty; - idx[i] = j + 1; - break; - } - } - else { - env[2 * i + 1] = (jl_value_t*)tv; - complete = 0; - } - } - } - JL_GC_POP(); - return complete; -} -#endif -#if 0 -static int _compile_all_union(jl_tupletype_t *sig, jl_svec_t *tvars) -{ - // f(::Union{...}, ...) is a common pattern - // and expanding the Union may give a leaf function - int complete = 1; - size_t count_unions = 0; - size_t i, l = jl_svec_len(sig->parameters); - jl_svec_t *p = NULL; - jl_tupletype_t *methsig = NULL; - - for (i = 0; i < l; i++) { - jl_value_t *ty = jl_svecref(sig->parameters, i); - if (jl_is_uniontype(ty)) { - jl_svec_t *utypes = ((jl_uniontype_t*)ty)->types; - size_t l = jl_svec_len(utypes); - if (l == 0) - return 1; // why does this method exist? - ++count_unions; - } - } - - //if (count_unions == 0) - // return _compile_all_tvar_union(sig, tvars); - - int *idx = (int*)alloca(sizeof(int) * count_unions); - for (i = 0; i < count_unions; i++) { - idx[i] = 0; - } - - JL_GC_PUSH2(&p, &methsig); - int idx_ctr = 0, incr = 0; - while (!incr) { - jl_svec_t *p = jl_alloc_svec_uninit(l); - for (i = 0, idx_ctr = 0, incr = 1; i < l; i++) { - jl_value_t *ty = jl_svecref(sig->parameters, i); - if (jl_is_uniontype(ty)) { - jl_svec_t *utypes = ((jl_uniontype_t*)ty)->types; - size_t l = jl_svec_len(utypes); - size_t j = idx[idx_ctr]; - jl_svecset(p, i, jl_svecref(utypes, j)); - ++j; - if (incr) { - if (j == l) { - idx[idx_ctr] = 0; - } - else { - idx[idx_ctr] = j; - incr = 0; - } - } - ++idx_ctr; - } - else { - jl_svecset(p, i, ty); - } - } - methsig = jl_apply_tuple_type(p); - //if (!_compile_all_tvar_union(methsig, tvars)) - // complete = 0; - } - - JL_GC_POP(); - return complete; -} -#endif - -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 *linfo = NULL; - jl_code_info_t *src = NULL; - JL_GC_PUSH2(&linfo, &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; - jl_method_instance_t *linfo = m->unspecialized; - if (!linfo) { - linfo = jl_get_specialized(m, (jl_value_t*)ml->sig, jl_emptysvec); - m->unspecialized = linfo; - jl_gc_wb(m, linfo); - } - - //// infer this function now, if necessary - //if (linfo->jlcall_api == 2) - // continue; - //src = jl_type_infer(&linfo, jl_world_counter, 1); - //if (linfo->jlcall_api == 2) - // continue; - - // keep track of whether all possible signatures have been cached (and thus whether it can skip trying to compile the template function) - // this is necessary because many intrinsics try to call static_eval and thus are not compilable unspecialized - int complete = 0;//_compile_all_union(ml->sig, ml->tvars); - if (complete) { - if (linfo->fptr == NULL && linfo->functionObjectsDecls.functionObject == NULL) - // indicate that this method doesn't need to be compiled, because it was fully covered above - // TODO: do this some other way - linfo->fptr = (jl_fptr_t)(uintptr_t)-1; - } - else { - jl_compile_linfo(&linfo, src, jl_world_counter, &jl_default_cgparams); - assert(linfo->functionObjectsDecls.functionObject != NULL); - } - } - JL_GC_POP(); - jl_printf(JL_STDERR, "\n"); -} - -static int _compile_all_enq(jl_typemap_entry_t *ml, void *env) -{ - jl_array_t *found = (jl_array_t*)env; - // method definition -- compile template field - jl_method_t *m = ml->func.method; - if (!m->unspecialized || - (m->unspecialized->functionObjectsDecls.functionObject == NULL && - m->unspecialized->jlcall_api != 2 && - m->unspecialized->fptr == NULL)) { - // found a lambda that still needs to be compiled - jl_array_ptr_1d_push(found, (jl_value_t*)ml); - } - return 1; -} - -static void _compile_all_enq_module(jl_module_t *m, jl_array_t *found) -{ - // scan through all types reachable from 'v' and - // record all jl_method_instance_t objects and signatures in their method tables - size_t i, sz = m->bindings.size; - for(i=1; i < sz; i+=2) { - if (m->bindings.table[i] != HT_NOTFOUND) { - jl_binding_t *b = (jl_binding_t*)m->bindings.table[i]; - if (b->owner == m && b->value && b->constp) { - jl_value_t *v = b->value; - if (jl_is_datatype(v)) { - jl_typename_t *tn = ((jl_datatype_t*)v)->name; - if (tn->module == m && tn->name == b->name) { - jl_methtable_t *mt = tn->mt; - if (mt != NULL && (jl_value_t*)mt != jl_nothing) { - jl_typemap_visitor(mt->defs, _compile_all_enq, (void*)found); - } - } - } - else if (jl_is_module(v)) { - jl_module_t *child = (jl_module_t*)b->value; - if (child != m && child->parent == m && child->name == b->name) { - // this is the original/primary binding for the submodule - _compile_all_enq_module(child, found); - } - } - } - } - } -} - -static void jl_compile_all_defs(void) -{ - // 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) { - _compile_all_enq_module(jl_main_module, m); - size_t changes = jl_array_len(m); - if (!changes) - break; - _compile_all_deq(m); - jl_array_del_end(m, changes); - } - JL_GC_POP(); -} - -static int _precompile_enq_tfunc(jl_typemap_entry_t *l, void *closure) -{ - if (jl_is_method_instance(l->func.value) && - l->func.linfo->functionObjectsDecls.functionObject == NULL && - l->func.linfo->jlcall_api != 2) - jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)l->sig); - return 1; -} - -static int _precompile_enq_spec(jl_typemap_entry_t *def, void *closure) -{ - jl_typemap_visitor(def->func.method->specializations, _precompile_enq_tfunc, closure); - return 1; -} - -static void _precompile_enq_module(jl_module_t *m, jl_array_t *unspec) -{ - // removes all method caches - size_t i; - void **table = m->bindings.table; - for (i = 1; i < m->bindings.size; i += 2) { - if (table[i] != HT_NOTFOUND) { - jl_binding_t *b = (jl_binding_t*)table[i]; - if (b->owner == m && b->value && b->constp) { - if (jl_is_datatype(b->value)) { - jl_typename_t *tn = ((jl_datatype_t*)b->value)->name; - if (tn->module == m && tn->name == b->name) { - jl_methtable_t *mt = tn->mt; - if (mt != NULL && (jl_value_t*)mt != jl_nothing) { - jl_typemap_visitor(mt->defs, _precompile_enq_spec, (void*)unspec); - } - } - } - else if (jl_is_module(b->value)) { - jl_module_t *child = (jl_module_t*)b->value; - if (child != m && child->parent == m && child->name == b->name) { - // this is the original/primary binding for the submodule - _precompile_enq_module((jl_module_t*)b->value, unspec); - } - } - } - } - } -} - -static void jl_compile_specializations(void) -{ - // 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_GC_PUSH1(&m); - _precompile_enq_module(jl_main_module, m); - size_t i, l; - for (i = 0, l = jl_array_len(m); i < l; i++) { - jl_compile_hint((jl_tupletype_t*)jl_array_ptr_ref(m, i)); - } - JL_GC_POP(); -} - -void jl_precompile(int all) { - if (all) - jl_compile_all_defs(); - jl_compile_specializations(); -} - #ifdef JL_TRACE static int trace_en = 0; static int error_en = 1; @@ -2099,7 +1742,8 @@ jl_typemap_entry_t *call_cache[N_CALL_CACHE]; static uint8_t pick_which[N_CALL_CACHE]; #ifdef JL_GF_PROFILE size_t ncalls; -void call_cache_stats() { +void call_cache_stats() +{ int pick_which_stat[4] = {0, 0, 0, 0}; int i, count = 0; for (i = 0; i < N_CALL_CACHE; i++) { diff --git a/src/init.c b/src/init.c index 3cc3f04b22dcb3..778be20efb38b9 100644 --- a/src/init.c +++ b/src/init.c @@ -177,7 +177,7 @@ static void jl_uv_exitcleanup_walk(uv_handle_t *handle, void *arg) void jl_write_coverage_data(void); void jl_write_malloc_log(void); -static void julia_save(void); +void jl_write_compiler_output(void); static struct uv_shutdown_queue_item *next_shutdown_queue_item(struct uv_shutdown_queue_item *item) { @@ -193,7 +193,7 @@ void jl_uv_call_close_callback(jl_value_t *val); JL_DLLEXPORT void jl_atexit_hook(int exitcode) { jl_ptls_t ptls = jl_get_ptls_states(); - if (exitcode == 0) julia_save(); + if (exitcode == 0) jl_write_compiler_output(); jl_print_gc_stats(JL_STDERR); if (jl_options.code_coverage) jl_write_coverage_data(); @@ -710,74 +710,6 @@ void _julia_init(JL_IMAGE_SEARCH rel) jl_install_sigint_handler(); } -extern int asprintf(char **str, const char *fmt, ...); - -JL_DLLEXPORT int jl_generating_output(void) -{ - return jl_options.outputo || jl_options.outputbc || jl_options.outputji; -} - -void jl_precompile(int all); - -static void julia_save(void) -{ - if (!jl_generating_output()) - return; - - if (!jl_options.incremental) - jl_precompile(jl_options.compile_enabled == JL_OPTIONS_COMPILE_ALL); - - if (!jl_module_init_order) { - jl_printf(JL_STDERR, "WARNING: --output requested, but no modules defined during run\n"); - return; - } - - jl_array_t *worklist = jl_module_init_order; - JL_GC_PUSH1(&worklist); - jl_module_init_order = jl_alloc_vec_any(0); - int i, l = jl_array_len(worklist); - for (i = 0; i < l; i++) { - jl_value_t *m = jl_arrayref(worklist, i); - if (jl_get_global((jl_module_t*)m, jl_symbol("__init__"))) { - jl_array_ptr_1d_push(jl_module_init_order, m); - } - } - - if (jl_options.incremental) { - if (jl_options.outputji) - if (jl_save_incremental(jl_options.outputji, worklist)) - jl_exit(1); - if (jl_options.outputbc) - jl_printf(JL_STDERR, "WARNING: incremental output to a .bc file is not implemented\n"); - if (jl_options.outputo) - jl_printf(JL_STDERR, "WARNING: incremental output to a .o file is not implemented\n"); - } - else { - ios_t *s = NULL; - if (jl_options.outputo || jl_options.outputbc) - s = jl_create_system_image(); - - if (jl_options.outputji) { - if (s == NULL) { - jl_save_system_image(jl_options.outputji); - } - else { - ios_t f; - if (ios_file(&f, jl_options.outputji, 1, 1, 1, 1) == NULL) - jl_errorf("cannot open system image file \"%s\" for writing", jl_options.outputji); - ios_write(&f, (const char*)s->buf, (size_t)s->size); - ios_close(&f); - } - } - - if (jl_options.outputo || jl_options.outputbc) - jl_dump_native(jl_options.outputbc, - jl_options.outputo, - (const char*)s->buf, (size_t)s->size); - } - JL_GC_POP(); -} - static jl_value_t *core(const char *name) { return jl_get_global(jl_core_module, jl_symbol(name));