From 13e954ed54c1a221053885fb605c619223fddb8a Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 30 May 2025 16:26:33 +0000 Subject: [PATCH] fix `@invokelatest` performance regression A bit of hacking to get back near to the same performance as before by using the GlobalRef to optimize the getglobal lookup for now and avoiding the extra Vararg function indirection which forced some extra boxing and lookups. julia> @btime foo(1.5) 22.892 ns (1 allocation: 16 bytes) # v1.11 141.543 ns (3 allocations: 48 bytes) # master 38.759 ns (2 allocations: 32 bytes) # PR The remaining difference is split about equally between the need now to box the world counter value for invoke_in_world and the extra cost of scanning the partition table for `Base.sin` to find the current entry. Fix #58334 --- base/reflection.jl | 11 +++++---- src/ast.c | 2 +- src/builtins.c | 2 +- src/gf.c | 6 ++--- src/init.c | 4 ++-- src/interpreter.c | 12 +++++----- src/jl_uv.c | 3 ++- src/jlapi.c | 2 +- src/jltypes.c | 1 + src/julia.h | 2 -- src/julia_internal.h | 5 +++- src/module.c | 12 +++++----- src/precompile.c | 4 ++-- src/rtutils.c | 5 ++-- src/scheduler.c | 2 +- src/staticdata_utils.c | 14 +++++------ src/task.c | 2 +- src/threading.c | 2 +- src/toplevel.c | 37 ++++++++++++++++-------------- stdlib/REPL/src/REPLCompletions.jl | 2 +- 20 files changed, 69 insertions(+), 61 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index 304683639b6d3..edc1afc8a6aaf 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1269,16 +1269,17 @@ macro invoke(ex) return esc(out) end -apply_gr(gr::GlobalRef, @nospecialize args...) = getglobal(gr.mod, gr.name)(args...) -apply_gr_kw(@nospecialize(kwargs::NamedTuple), gr::GlobalRef, @nospecialize args...) = Core.kwcall(kwargs, getglobal(gr.mod, gr.name), args...) +getglobalref(gr::GlobalRef, world::UInt) = ccall(:jl_eval_globalref, Any, (Any, UInt), gr, world) -function invokelatest_gr(gr::GlobalRef, @nospecialize args...; kwargs...) +function invokelatest_gr(gr::GlobalRef, args...; kwargs...) @inline kwargs = merge(NamedTuple(), kwargs) + world = get_world_counter() + f = getglobalref(gr, world) if isempty(kwargs) - return invokelatest(apply_gr, gr, args...) + return invoke_in_world(world, f, args...) end - return invokelatest(apply_gr_kw, kwargs, gr, args...) + return invoke_in_world(world, Core.kwcall, kwargs, f, args...) end """ diff --git a/src/ast.c b/src/ast.c index 8f36cd06decad..fdb29349a0db6 100644 --- a/src/ast.c +++ b/src/ast.c @@ -1328,7 +1328,7 @@ JL_DLLEXPORT jl_value_t *jl_lower(jl_value_t *expr, jl_module_t *inmodule, { jl_value_t *core_lower = NULL; if (jl_core_module) - core_lower = jl_get_global_value(jl_core_module, jl_symbol("_lower")); + core_lower = jl_get_global_value(jl_core_module, jl_symbol("_lower"), jl_current_task->world_age); if (!core_lower || core_lower == jl_nothing) { return jl_fl_lower(expr, inmodule, filename, line, world, warn); } diff --git a/src/builtins.c b/src/builtins.c index 0e309ab912f9c..46fceb91f86e7 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1340,7 +1340,7 @@ JL_CALLABLE(jl_f_getglobal) jl_atomic_error("getglobal: module binding cannot be read non-atomically"); else if (order >= jl_memory_order_seq_cst) jl_fence(); - jl_value_t *v = jl_eval_global_var(mod, sym); // relaxed load + jl_value_t *v = jl_eval_global_var(mod, sym, jl_current_task->world_age); // relaxed load if (order >= jl_memory_order_acquire) jl_fence(); return v; diff --git a/src/gf.c b/src/gf.c index 6e2403826b7f1..8205cf70b99c3 100644 --- a/src/gf.c +++ b/src/gf.c @@ -512,13 +512,13 @@ JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t w ct->world_age = jl_typeinf_world; jl_value_t **fargs; JL_GC_PUSHARGS(fargs, 4); - jl_module_t *CC = (jl_module_t*)jl_get_global_value(jl_core_module, jl_symbol("Compiler")); + jl_module_t *CC = (jl_module_t*)jl_get_global_value(jl_core_module, jl_symbol("Compiler"), ct->world_age); if (CC != NULL && jl_is_module(CC)) { JL_GC_PROMISE_ROOTED(CC); - fargs[0] = jl_get_global_value(CC, jl_symbol("NativeInterpreter"));; + fargs[0] = jl_get_global_value(CC, jl_symbol("NativeInterpreter"), ct->world_age); fargs[1] = jl_box_ulong(world); fargs[1] = jl_apply(fargs, 2); - fargs[0] = jl_get_global_value(CC, jl_symbol("typeinf_code")); + fargs[0] = jl_get_global_value(CC, jl_symbol("typeinf_code"), ct->world_age); fargs[2] = (jl_value_t*)mi; fargs[3] = jl_true; ci = (jl_code_info_t*)jl_apply(fargs, 4); diff --git a/src/init.c b/src/init.c index f811cf76748fb..a64f43c62f776 100644 --- a/src/init.c +++ b/src/init.c @@ -249,7 +249,7 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NOTSAFEPOINT_ENTER if (jl_base_module) { size_t last_age = ct->world_age; ct->world_age = jl_get_world_counter(); - jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_atexit")); + jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_atexit"), ct->world_age); if (f != NULL) { jl_value_t **fargs; JL_GC_PUSHARGS(fargs, 2); @@ -357,7 +357,7 @@ JL_DLLEXPORT void jl_postoutput_hook(void) jl_task_t *ct = jl_get_current_task(); size_t last_age = ct->world_age; ct->world_age = jl_get_world_counter(); - jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_postoutput")); + jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_postoutput"), ct->world_age); if (f != NULL) { JL_TRY { JL_GC_PUSH1(&f); diff --git a/src/interpreter.c b/src/interpreter.c index aa89f7385532f..c4de34da37ce9 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -162,18 +162,18 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state } // get the global (throwing if null) in the current world -jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e) +jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e, size_t world) { - jl_value_t *v = jl_get_global_value(m, e); + jl_value_t *v = jl_get_global_value(m, e, world); if (v == NULL) jl_undefined_var_error(e, (jl_value_t*)m); return v; } // get the global (throwing if null) in the current world, optimized -jl_value_t *jl_eval_globalref(jl_globalref_t *g) +jl_value_t *jl_eval_globalref(jl_globalref_t *g, size_t world) { - jl_value_t *v = jl_get_globalref_value(g); + jl_value_t *v = jl_get_globalref_value(g, world); if (v == NULL) jl_undefined_var_error(g->name, (jl_value_t*)g->mod); return v; @@ -218,10 +218,10 @@ static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s) return jl_quotenode_value(e); } if (jl_is_globalref(e)) { - return jl_eval_globalref((jl_globalref_t*)e); + return jl_eval_globalref((jl_globalref_t*)e, jl_current_task->world_age); } if (jl_is_symbol(e)) { // bare symbols appear in toplevel exprs not wrapped in `thunk` - return jl_eval_global_var(s->module, (jl_sym_t*)e); + return jl_eval_global_var(s->module, (jl_sym_t*)e, jl_current_task->world_age); } if (jl_is_pinode(e)) { jl_value_t *val = eval_value(jl_fieldref_noalloc(e, 0), s); diff --git a/src/jl_uv.c b/src/jl_uv.c index 005d1ea727655..a21b05433b8c6 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -162,7 +162,8 @@ static void jl_uv_call_close_callback(jl_value_t *val) JL_GC_PUSHARGS(args, 2); // val is "rooted" in the finalizer list only right now args[0] = jl_eval_global_var( jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module), - jl_symbol("_uv_hook_close")); // topmod(typeof(val))._uv_hook_close + jl_symbol("_uv_hook_close"), + jl_current_task->world_age); // topmod(typeof(val))._uv_hook_close args[1] = val; jl_apply(args, 2); // TODO: wrap in try-catch? JL_GC_POP(); diff --git a/src/jlapi.c b/src/jlapi.c index e127fd1367816..0d8ddd10d9ea1 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -955,7 +955,7 @@ static NOINLINE int true_main(int argc, char *argv[]) ct->world_age = jl_get_world_counter(); jl_function_t *start_client = jl_base_module ? - (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("_start")) : NULL; + (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("_start"), ct->world_age) : NULL; if (start_client) { int ret = 1; diff --git a/src/jltypes.c b/src/jltypes.c index fcb15a1a9a69d..7d731082bd786 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3287,6 +3287,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_perm_symsvec(3, "mod", "name", "binding"), jl_svec(3, jl_module_type, jl_symbol_type, jl_binding_type), jl_emptysvec, 0, 0, 3); + jl_globalref_type->name->mayinlinealloc = 0; // not at all worthwhile, since the only constructor returns a boxed object jl_core_module = jl_new_module(jl_symbol("Core"), NULL); diff --git a/src/julia.h b/src/julia.h index 4a4a4eff81232..03a0185800d12 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2094,9 +2094,7 @@ JL_DLLEXPORT jl_value_t *jl_get_existing_strong_gf(jl_binding_t *b JL_PROPAGATES JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import); JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr); -JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr); JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); -JL_DLLEXPORT jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); void jl_set_initial_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT, int exported); diff --git a/src/julia_internal.h b/src/julia_internal.h index b94011e17a3e3..24fb7fdb05f90 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -901,7 +901,10 @@ STATIC_INLINE size_t module_usings_max(jl_module_t *m) JL_NOTSAFEPOINT { JL_DLLEXPORT jl_sym_t *jl_module_name(jl_module_t *m) JL_NOTSAFEPOINT; void jl_add_scanned_method(jl_module_t *m, jl_method_t *meth); -jl_value_t *jl_eval_global_var(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *e); +jl_value_t *jl_eval_global_var(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *e, size_t world); +JL_DLLEXPORT jl_value_t *jl_eval_globalref(jl_globalref_t *g, size_t world); +jl_value_t *jl_get_globalref_value(jl_globalref_t *gr, size_t world); +jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var, size_t world); jl_value_t *jl_interpret_opaque_closure(jl_opaque_closure_t *clos, jl_value_t **args, size_t nargs); jl_value_t *jl_interpret_toplevel_thunk(jl_module_t *m, jl_code_info_t *src); jl_value_t *jl_interpret_toplevel_expr_in(jl_module_t *m, jl_value_t *e, diff --git a/src/module.c b/src/module.c index f154b7d29db8e..8c6c86b144f38 100644 --- a/src/module.c +++ b/src/module.c @@ -1540,20 +1540,20 @@ JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m, jl_sym_t *var, } -// get the value (or null) in the current world -JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr) +// get the value (or null) in the world +jl_value_t *jl_get_globalref_value(jl_globalref_t *gr, size_t world) { jl_binding_t *b = gr->binding; if (!b) b = jl_get_module_binding(gr->mod, gr->name, 1); - return jl_get_binding_value_depwarn(b, jl_current_task->world_age); + return jl_get_binding_value_depwarn(b, world); } -// get the value (or null) in the current world -JL_DLLEXPORT jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var) +// get the value (or null) in the world +jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var, size_t world) { jl_binding_t *b = jl_get_module_binding(m, var, 1); - return jl_get_binding_value_depwarn(b, jl_current_task->world_age); + return jl_get_binding_value_depwarn(b, world); } // get the global (or null) in the latest world diff --git a/src/precompile.c b/src/precompile.c index 33b71d4605b30..a6ec4d550cfba 100644 --- a/src/precompile.c +++ b/src/precompile.c @@ -45,8 +45,8 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) { size_t last_age = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); JL_GC_PUSH4(&deptuple, &depots, &replace_depot_func, &normalize_depots_func); - replace_depot_func = jl_eval_global_var(jl_base_module, jl_symbol("replace_depot_path")); - normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation")); + replace_depot_func = jl_eval_global_var(jl_base_module, jl_symbol("replace_depot_path"), jl_current_task->world_age); + normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation"), jl_current_task->world_age); depots = jl_apply(&normalize_depots_func, 1); jl_datatype_t *deptuple_p[5] = {jl_module_type, jl_string_type, jl_uint64_type, jl_uint32_type, jl_float64_type}; jl_value_t *jl_deptuple_type = jl_apply_tuple_type_v((jl_value_t**)deptuple_p, 5); diff --git a/src/rtutils.c b/src/rtutils.c index 1f341ee60c972..28454187c6ba7 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -1603,10 +1603,11 @@ void jl_log(int level, jl_value_t *module, jl_value_t *group, jl_value_t *id, jl_value_t *msg) { jl_value_t *logmsg_func = NULL; + jl_task_t *ct = jl_current_task; if (jl_base_module) { - jl_value_t *corelogging = jl_get_global_value(jl_base_module, jl_symbol("CoreLogging")); + jl_value_t *corelogging = jl_get_global_value(jl_base_module, jl_symbol("CoreLogging"), ct->world_age); if (corelogging && jl_is_module(corelogging)) { - logmsg_func = jl_get_global_value((jl_module_t*)corelogging, jl_symbol("logmsg_shim")); + logmsg_func = jl_get_global_value((jl_module_t*)corelogging, jl_symbol("logmsg_shim"), ct->world_age); } } if (!logmsg_func) { diff --git a/src/scheduler.c b/src/scheduler.c index 8e0202cc7a980..b13e4072c7d73 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -331,7 +331,7 @@ void jl_task_wait_empty(void) jl_wait_empty_begin(); size_t lastage = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); - jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("wait")); + jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("wait"), ct->world_age); wait_empty = ct; if (f) { JL_GC_PUSH1(&f); diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 3f05de189c3ef..0b8cfc1cf4ebd 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -544,21 +544,21 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t jl_value_t *get_compiletime_prefs_func = NULL; JL_GC_PUSH8(&depots, &prefs_list, &unique_func, &replace_depot_func, &normalize_depots_func, &toplevel, &prefs_hash_func, &get_compiletime_prefs_func); - jl_array_t *udeps = (jl_array_t*)jl_get_global_value(jl_base_module, jl_symbol("_require_dependencies")); + jl_array_t *udeps = (jl_array_t*)jl_get_global_value(jl_base_module, jl_symbol("_require_dependencies"), ct->world_age); *udepsp = udeps; // unique(udeps) to eliminate duplicates while preserving order: // we preserve order so that the topmost included .jl file comes first if (udeps) { - unique_func = jl_eval_global_var(jl_base_module, jl_symbol("unique")); + unique_func = jl_eval_global_var(jl_base_module, jl_symbol("unique"), ct->world_age); jl_value_t *uniqargs[2] = {unique_func, (jl_value_t*)udeps}; udeps = (jl_array_t*)jl_apply(uniqargs, 2); *udepsp = udeps; JL_TYPECHK(write_dependency_list, array_any, (jl_value_t*)udeps); } - replace_depot_func = jl_get_global_value(jl_base_module, jl_symbol("replace_depot_path")); - normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation")); + replace_depot_func = jl_get_global_value(jl_base_module, jl_symbol("replace_depot_path"), ct->world_age); + normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation"), ct->world_age); depots = jl_apply(&normalize_depots_func, 1); @@ -616,9 +616,9 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t // Calculate Preferences hash for current package. if (jl_base_module) { // Toplevel module is the module we're currently compiling, use it to get our preferences hash - toplevel = jl_get_global_value(jl_base_module, jl_symbol("__toplevel__")); - prefs_hash_func = jl_eval_global_var(jl_base_module, jl_symbol("get_preferences_hash")); - get_compiletime_prefs_func = jl_eval_global_var(jl_base_module, jl_symbol("get_compiletime_preferences")); + toplevel = jl_get_global_value(jl_base_module, jl_symbol("__toplevel__"), ct->world_age); + prefs_hash_func = jl_eval_global_var(jl_base_module, jl_symbol("get_preferences_hash"), ct->world_age); + get_compiletime_prefs_func = jl_eval_global_var(jl_base_module, jl_symbol("get_compiletime_preferences"), ct->world_age); if (toplevel) { // call get_compiletime_prefs(__toplevel__) diff --git a/src/task.c b/src/task.c index 5804be8bff1a9..f8367a514572c 100644 --- a/src/task.c +++ b/src/task.c @@ -335,7 +335,7 @@ void JL_NORETURN jl_finish_task(jl_task_t *ct) // let the runtime know this task is dead and find a new task to run jl_function_t *done = jl_atomic_load_relaxed(&task_done_hook_func); if (done == NULL) { - done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("task_done_hook")); + done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("task_done_hook"), ct->world_age); if (done != NULL) jl_atomic_store_release(&task_done_hook_func, done); } diff --git a/src/threading.c b/src/threading.c index 37e5ac3b856a3..11726f5452cf0 100644 --- a/src/threading.c +++ b/src/threading.c @@ -413,7 +413,7 @@ static void jl_init_task_lock(jl_task_t *ct) ct->world_age = jl_get_world_counter(); jl_function_t *done = jl_atomic_load_relaxed(&init_task_lock_func); if (done == NULL) { - done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("init_task_lock")); + done = (jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("init_task_lock"), ct->world_age); if (done != NULL) jl_atomic_store_release(&init_task_lock_func, done); } diff --git a/src/toplevel.c b/src/toplevel.c index 7b20c5df19b12..8540d8e5f3c56 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -62,7 +62,7 @@ void jl_module_run_initializer(jl_module_t *m) size_t last_age = ct->world_age; JL_TRY { ct->world_age = jl_atomic_load_acquire(&jl_world_counter); - jl_value_t *f = jl_get_global_value(m, jl_symbol("__init__")); + jl_value_t *f = jl_get_global_value(m, jl_symbol("__init__"), ct->world_age); if (f != NULL) { JL_GC_PUSH1(&f); jl_apply(&f, 1); @@ -104,10 +104,10 @@ jl_array_t *jl_get_loaded_modules(void) return NULL; } -static int jl_is__toplevel__mod(jl_module_t *mod) +static int jl_is__toplevel__mod(jl_module_t *mod, jl_task_t *ct) { return jl_base_module && - (jl_value_t*)mod == jl_get_global_value(jl_base_module, jl_symbol("__toplevel__")); + (jl_value_t*)mod == jl_get_global_value(jl_base_module, jl_symbol("__toplevel__"), ct->world_age); } // TODO: add locks around global state mutation operations @@ -129,7 +129,7 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex jl_type_error("module", (jl_value_t*)jl_symbol_type, (jl_value_t*)name); } - int is_parent__toplevel__ = jl_is__toplevel__mod(parent_module); + int is_parent__toplevel__ = jl_is__toplevel__mod(parent_module, ct); // If we have `Base`, don't also try to import `Core` - the `Base` exports are a superset. // While we allow multiple imports of the same binding from different modules, various error printing // performs reflection on which module a binding came from and we'd prefer users see "Base" here. @@ -247,19 +247,18 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex return (jl_value_t*)newm; } -static jl_value_t *jl_eval_dot_expr(jl_module_t *m, jl_value_t *x, jl_value_t *f, int fast, const char **toplevel_filename, int *toplevel_lineno) +static jl_value_t *jl_eval_dot_expr(jl_task_t *ct, jl_module_t *m, jl_value_t *x, jl_value_t *f, int fast, const char **toplevel_filename, int *toplevel_lineno) { - jl_task_t *ct = jl_current_task; jl_value_t **args; JL_GC_PUSHARGS(args, 3); args[1] = jl_toplevel_eval_flex(m, x, fast, 0, toplevel_filename, toplevel_lineno); args[2] = jl_toplevel_eval_flex(m, f, fast, 0, toplevel_filename, toplevel_lineno); if (jl_is_module(args[1])) { JL_TYPECHK(getglobal, symbol, args[2]); - args[0] = jl_eval_global_var((jl_module_t*)args[1], (jl_sym_t*)args[2]); + args[0] = jl_eval_global_var((jl_module_t*)args[1], (jl_sym_t*)args[2], ct->world_age); } else { - args[0] = jl_eval_global_var(jl_base_relative_to(m), jl_symbol("getproperty")); + args[0] = jl_eval_global_var(jl_base_relative_to(m), jl_symbol("getproperty"), ct->world_age); size_t last_age = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); args[0] = jl_apply(args, 3); @@ -604,6 +603,16 @@ JL_DLLEXPORT void jl_eval_const_decl(jl_module_t *m, jl_value_t *arg, jl_value_t JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_value_t *e, int fast, int expanded, const char **toplevel_filename, int *toplevel_lineno) { jl_task_t *ct = jl_current_task; + if (jl_is_globalref(e)) { + return jl_eval_globalref((jl_globalref_t*)e, ct->world_age); + } + if (jl_is_symbol(e)) { + char *n = jl_symbol_name((jl_sym_t*)e), *n0 = n; + while (*n == '_') ++n; + if (*n == 0 && n > n0) + jl_eval_errorf(m, *toplevel_filename, *toplevel_lineno, "all-underscore identifiers are write-only and their values cannot be used in expressions"); + return jl_eval_global_var(m, (jl_sym_t*)e, ct->world_age); + } if (!jl_is_expr(e)) { if (jl_is_linenode(e)) { *toplevel_lineno = jl_linenode_line(e); @@ -617,12 +626,6 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val jl_lineno = *toplevel_lineno; return jl_nothing; } - if (jl_is_symbol(e)) { - char *n = jl_symbol_name((jl_sym_t*)e), *n0 = n; - while (*n == '_') ++n; - if (*n == 0 && n > n0) - jl_eval_errorf(m, *toplevel_filename, *toplevel_lineno, "all-underscore identifiers are write-only and their values cannot be used in expressions"); - } return jl_interpret_toplevel_expr_in(m, e, NULL, NULL); } @@ -635,7 +638,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val jl_value_t *rhs = jl_exprarg(ex, 1); // only handle `a.b` syntax here, so qualified names can be eval'd in pure contexts if (jl_is_quotenode(rhs) && jl_is_symbol(jl_fieldref(rhs, 0))) { - return jl_eval_dot_expr(m, lhs, rhs, fast, toplevel_filename, toplevel_lineno); + return jl_eval_dot_expr(ct, m, lhs, rhs, fast, toplevel_filename, toplevel_lineno); } } @@ -727,7 +730,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val } else if (jl_is_symbol(ex)) { JL_GC_POP(); - return jl_eval_global_var(m, (jl_sym_t*)ex); + return jl_eval_global_var(m, (jl_sym_t*)ex, ct->world_age); } else if (head == NULL) { JL_GC_POP(); @@ -804,7 +807,7 @@ JL_DLLEXPORT void jl_check_top_level_effect(jl_module_t *m, char *fname) } } JL_UNLOCK(&jl_modules_mutex); - if (!open && !jl_is__toplevel__mod(m)) { + if (!open && !jl_is__toplevel__mod(m, jl_current_task)) { const char* name = jl_symbol_name(m->name); jl_errorf("Evaluation into the closed module `%s` breaks incremental compilation " "because the side effects will not be permanent. " diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 8b8fb64b07dae..8e2983b7540e0 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -609,7 +609,7 @@ function CC.builtin_tfunction(interp::REPLInterpreter, @nospecialize(f), if isa(a1val, Module) && isa(a2val, Symbol) g = GlobalRef(a1val, a2val) if isdefined_globalref(g) - return Const(ccall(:jl_get_globalref_value, Any, (Any,), g)) + return Const(ccall(:jl_eval_globalref, Any, (Any, UInt), g, tls_world_age())) end return Union{} end