From 8a1d443231083dff8e8a0bf7ab54c0d98a9687f8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 30 Jul 2015 23:02:31 -0400 Subject: [PATCH] print a warning when a module is unlikely to be successful at incremental compilation (close #12352) calling eval into another module during compile-time is almost guaranteed to break incremental compilation the usual symptom would be a segfault during deserialization due to the existance of a type, module, or other data structure in the 'other' module that will not be persisted. it is also possible to 'lose' method definitions because their lambda_info->module field will be assigned incorrectly --- base/serialize.jl | 2 +- src/alloc.c | 4 ++-- src/ast.c | 4 ++-- src/builtins.c | 21 +++++++++++++++++++-- src/gf.c | 5 ++--- src/jlfrontend.scm | 8 +------- src/julia.h | 5 +++-- src/toplevel.c | 5 +++-- 8 files changed, 33 insertions(+), 21 deletions(-) diff --git a/base/serialize.jl b/base/serialize.jl index e2fe9baa3df6f..afd57c6fd6bec 100644 --- a/base/serialize.jl +++ b/base/serialize.jl @@ -534,7 +534,7 @@ function deserialize(s::SerializationState, ::Type{LambdaStaticData}) linfo = known_lambda_data[lnumber]::LambdaStaticData makenew = false else - linfo = ccall(:jl_new_lambda_info, Any, (Ptr{Void}, Ptr{Void}), C_NULL, C_NULL)::LambdaStaticData + linfo = ccall(:jl_new_lambda_info, Any, (Ptr{Void}, Ptr{Void}, Ptr{Void}), C_NULL, C_NULL, C_NULL)::LambdaStaticData makenew = true end deserialize_cycle(s, linfo) diff --git a/src/alloc.c b/src/alloc.c index dd431d0e04a01..c6d57c5953d4e 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -324,7 +324,7 @@ DLLEXPORT jl_function_t *jl_new_closure(jl_fptr_t fptr, jl_value_t *env, } DLLEXPORT -jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *sparams) +jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *sparams, jl_module_t *ctx) { jl_lambda_info_t *li = (jl_lambda_info_t*)newobj((jl_value_t*)jl_lambda_info_type, @@ -339,7 +339,7 @@ jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *sparams) li->line = jl_unbox_long(jl_exprarg(body1, 0)); } } - li->module = jl_current_module; + li->module = ctx; li->sparams = sparams; li->tfunc = jl_nothing; li->fptr = &jl_trampoline; diff --git a/src/ast.c b/src/ast.c index f957c631b8dc0..de15549174c47 100644 --- a/src/ast.c +++ b/src/ast.c @@ -319,7 +319,7 @@ static jl_value_t *scm_to_julia_(value_t e, int eo) jl_cellset(ex->args, i, scm_to_julia_(car_(e), eo)); e = cdr_(e); } - jl_lambda_info_t *nli = jl_new_lambda_info((jl_value_t*)ex, jl_emptysvec); + jl_lambda_info_t *nli = jl_new_lambda_info((jl_value_t*)ex, jl_emptysvec, jl_current_module); resolve_globals(nli->ast, nli); return (jl_value_t*)nli; } @@ -639,7 +639,7 @@ jl_lambda_info_t *jl_wrap_expr(jl_value_t *expr) expr = (jl_value_t*)bo; } jl_cellset(le->args, 2, expr); - jl_lambda_info_t *li = jl_new_lambda_info((jl_value_t*)le, jl_emptysvec); + jl_lambda_info_t *li = jl_new_lambda_info((jl_value_t*)le, jl_emptysvec, jl_current_module); JL_GC_POP(); return li; } diff --git a/src/builtins.c b/src/builtins.c index 7a99461524e67..eca074999e337 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -537,8 +537,10 @@ JL_CALLABLE(jl_f_kwcall) extern int jl_lineno; -DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex) +DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex, int delay_warn) { + static int jl_warn_on_eval = 0; + int last_delay_warn = jl_warn_on_eval; if (m == NULL) m = jl_main_module; if (jl_is_symbol(ex)) @@ -547,16 +549,31 @@ DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex) int last_lineno = jl_lineno; jl_module_t *last_m = jl_current_module; jl_module_t *task_last_m = jl_current_task->current_module; + if (!delay_warn && jl_options.incremental && jl_generating_output()) { + if (m != last_m) { + jl_printf(JL_STDERR, "WARNING: eval from module %s to %s: \n", m->name->name, last_m->name->name); + jl_static_show(JL_STDERR, ex); + jl_printf(JL_STDERR, "\n ** incremental compilation may be broken for this module **\n\n"); + } + else if (jl_warn_on_eval) { + jl_printf(JL_STDERR, "WARNING: eval from staged function in module %s: \n", m->name->name); + jl_static_show(JL_STDERR, ex); + jl_printf(JL_STDERR, "\n ** incremental compilation may be broken for these modules **\n\n"); + } + } JL_TRY { + jl_warn_on_eval = delay_warn && (jl_warn_on_eval || m != last_m); // compute whether a warning was suppressed jl_current_task->current_module = jl_current_module = m; v = jl_toplevel_eval(ex); } JL_CATCH { + jl_warn_on_eval = last_delay_warn; jl_lineno = last_lineno; jl_current_module = last_m; jl_current_task->current_module = task_last_m; jl_rethrow(); } + jl_warn_on_eval = last_delay_warn; jl_lineno = last_lineno; jl_current_module = last_m; jl_current_task->current_module = task_last_m; @@ -578,7 +595,7 @@ JL_CALLABLE(jl_f_top_eval) m = (jl_module_t*)args[0]; ex = args[1]; } - return jl_toplevel_eval_in(m, ex); + return jl_toplevel_eval_in(m, ex, 0); } JL_CALLABLE(jl_f_isdefined) diff --git a/src/gf.c b/src/gf.c index b670567774ec8..a2605cbaa2e73 100644 --- a/src/gf.c +++ b/src/gf.c @@ -294,10 +294,9 @@ jl_lambda_info_t *jl_add_static_parameters(jl_lambda_info_t *l, jl_svec_t *sp) JL_GC_PUSH1(&sp); if (jl_svec_len(l->sparams) > 0) sp = jl_svec_append(sp, l->sparams); - jl_lambda_info_t *nli = jl_new_lambda_info(l->ast, sp); + jl_lambda_info_t *nli = jl_new_lambda_info(l->ast, sp, l->module); nli->name = l->name; nli->fptr = l->fptr; - nli->module = l->module; nli->file = l->file; nli->line = l->line; nli->def = l->def; @@ -937,7 +936,7 @@ DLLEXPORT jl_function_t *jl_instantiate_staged(jl_methlist_t *m, jl_tupletype_t } ex = oldast; } - func = (jl_function_t*)jl_toplevel_eval_in(m->func->linfo->module, (jl_value_t*)ex); + func = (jl_function_t*)jl_toplevel_eval_in(m->func->linfo->module, (jl_value_t*)ex, 1); // need to eval macros in the right module, but not give a warning for the `eval` call unless that results in a call to `eval` func->linfo->name = m->func->linfo->name; JL_GC_POP(); return func; diff --git a/src/jlfrontend.scm b/src/jlfrontend.scm index 678c580f46dc7..41fa7bd740898 100644 --- a/src/jlfrontend.scm +++ b/src/jlfrontend.scm @@ -103,18 +103,12 @@ (pair? (cadr e)) (eq? (caadr e) '=) (symbol? (cadadr e)) (eq? (cadr (caddr e)) (cadadr e)))) -(define (lambda-ex? e) - (and (pair? e) (eq? (car e) 'lambda))) - (define (expand-toplevel-expr- e) (let ((ex (expand-toplevel-expr-- e))) (cond ((contains (lambda (x) (equal? x '(top ccall))) ex) ex) ((simple-assignment? ex) (cadr ex)) - ((and (length= ex 2) (eq? (car ex) 'body) - (not (lambda-ex? (cadadr ex)))) + ((and (length= ex 2) (eq? (car ex) 'body)) ;; (body (return x)) => x - ;; if x is not a lambda expr, so we don't think it is a thunk - ;; to be called immediately. (cadadr ex)) (else ex)))) diff --git a/src/julia.h b/src/julia.h index cf8a3ffb904cc..7d02dd011e71f 100644 --- a/src/julia.h +++ b/src/julia.h @@ -898,7 +898,7 @@ DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uin DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type); DLLEXPORT jl_function_t *jl_new_closure(jl_fptr_t proc, jl_value_t *env, jl_lambda_info_t *li); -DLLEXPORT jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *sparams); +DLLEXPORT jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *sparams, jl_module_t *ctx); DLLEXPORT jl_svec_t *jl_svec(size_t n, ...); DLLEXPORT jl_svec_t *jl_svec1(void *a); DLLEXPORT jl_svec_t *jl_svec2(void *a, void *b); @@ -1149,6 +1149,7 @@ jl_value_t *jl_parse_next(void); DLLEXPORT jl_value_t *jl_load_file_string(const char *text, size_t len, char *filename, size_t namelen); DLLEXPORT jl_value_t *jl_expand(jl_value_t *expr); +DLLEXPORT jl_value_t *jl_expand_in(jl_module_t *module, jl_value_t *expr); jl_lambda_info_t *jl_wrap_expr(jl_value_t *expr); DLLEXPORT void *jl_eval_string(const char *str); @@ -1184,7 +1185,7 @@ DLLEXPORT const char *jl_lookup_soname(const char *pfx, size_t n); // compiler void jl_compile(jl_function_t *f); DLLEXPORT jl_value_t *jl_toplevel_eval(jl_value_t *v); -DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex); +DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex, int delay_warn); jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e); DLLEXPORT jl_value_t *jl_load(const char *fname, size_t len); jl_value_t *jl_parse_eval_all(const char *fname, size_t len); diff --git a/src/toplevel.c b/src/toplevel.c index 5cad04f66a5c1..44bdd83092ac1 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -58,6 +58,8 @@ jl_module_t *jl_new_main_module(void) jl_main_module = jl_new_module(jl_symbol("Main")); jl_main_module->parent = jl_main_module; + if (old_main) // don't block continued loading of incremental caches + jl_main_module->uuid = old_main->uuid; jl_current_module = jl_main_module; jl_core_module->parent = jl_main_module; @@ -700,14 +702,13 @@ DLLEXPORT jl_value_t *jl_generic_function_def(jl_sym_t *name, jl_value_t **bp, j static jl_lambda_info_t *jl_copy_lambda_info(jl_lambda_info_t *linfo) { jl_lambda_info_t *new_linfo = - jl_new_lambda_info(linfo->ast, linfo->sparams); + jl_new_lambda_info(linfo->ast, linfo->sparams, linfo->module); new_linfo->tfunc = linfo->tfunc; new_linfo->name = linfo->name; new_linfo->roots = linfo->roots; new_linfo->specTypes = linfo->specTypes; new_linfo->unspecialized = linfo->unspecialized; new_linfo->specializations = linfo->specializations; - new_linfo->module = linfo->module; new_linfo->def = linfo->def; new_linfo->capt = linfo->capt; new_linfo->file = linfo->file;