Skip to content

Commit f12256b

Browse files
authored
fix @invokelatest performance regression (#58582)
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
1 parent 6f12957 commit f12256b

File tree

19 files changed

+68
-60
lines changed

19 files changed

+68
-60
lines changed

base/reflection.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,16 +1269,17 @@ macro invoke(ex)
12691269
return esc(out)
12701270
end
12711271

1272-
apply_gr(gr::GlobalRef, @nospecialize args...) = getglobal(gr.mod, gr.name)(args...)
1273-
apply_gr_kw(@nospecialize(kwargs::NamedTuple), gr::GlobalRef, @nospecialize args...) = Core.kwcall(kwargs, getglobal(gr.mod, gr.name), args...)
1272+
getglobalref(gr::GlobalRef, world::UInt) = ccall(:jl_eval_globalref, Any, (Any, UInt), gr, world)
12741273

1275-
function invokelatest_gr(gr::GlobalRef, @nospecialize args...; kwargs...)
1274+
function invokelatest_gr(gr::GlobalRef, args...; kwargs...)
12761275
@inline
12771276
kwargs = merge(NamedTuple(), kwargs)
1277+
world = get_world_counter()
1278+
f = getglobalref(gr, world)
12781279
if isempty(kwargs)
1279-
return invokelatest(apply_gr, gr, args...)
1280+
return invoke_in_world(world, f, args...)
12801281
end
1281-
return invokelatest(apply_gr_kw, kwargs, gr, args...)
1282+
return invoke_in_world(world, Core.kwcall, kwargs, f, args...)
12821283
end
12831284

12841285
"""

src/ast.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1328,7 +1328,7 @@ JL_DLLEXPORT jl_value_t *jl_lower(jl_value_t *expr, jl_module_t *inmodule,
13281328
{
13291329
jl_value_t *core_lower = NULL;
13301330
if (jl_core_module)
1331-
core_lower = jl_get_global_value(jl_core_module, jl_symbol("_lower"));
1331+
core_lower = jl_get_global_value(jl_core_module, jl_symbol("_lower"), jl_current_task->world_age);
13321332
if (!core_lower || core_lower == jl_nothing) {
13331333
return jl_fl_lower(expr, inmodule, filename, line, world, warn);
13341334
}

src/builtins.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ JL_CALLABLE(jl_f_getglobal)
13401340
jl_atomic_error("getglobal: module binding cannot be read non-atomically");
13411341
else if (order >= jl_memory_order_seq_cst)
13421342
jl_fence();
1343-
jl_value_t *v = jl_eval_global_var(mod, sym); // relaxed load
1343+
jl_value_t *v = jl_eval_global_var(mod, sym, jl_current_task->world_age); // relaxed load
13441344
if (order >= jl_memory_order_acquire)
13451345
jl_fence();
13461346
return v;

src/gf.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -512,13 +512,13 @@ JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t w
512512
ct->world_age = jl_typeinf_world;
513513
jl_value_t **fargs;
514514
JL_GC_PUSHARGS(fargs, 4);
515-
jl_module_t *CC = (jl_module_t*)jl_get_global_value(jl_core_module, jl_symbol("Compiler"));
515+
jl_module_t *CC = (jl_module_t*)jl_get_global_value(jl_core_module, jl_symbol("Compiler"), ct->world_age);
516516
if (CC != NULL && jl_is_module(CC)) {
517517
JL_GC_PROMISE_ROOTED(CC);
518-
fargs[0] = jl_get_global_value(CC, jl_symbol("NativeInterpreter"));;
518+
fargs[0] = jl_get_global_value(CC, jl_symbol("NativeInterpreter"), ct->world_age);
519519
fargs[1] = jl_box_ulong(world);
520520
fargs[1] = jl_apply(fargs, 2);
521-
fargs[0] = jl_get_global_value(CC, jl_symbol("typeinf_code"));
521+
fargs[0] = jl_get_global_value(CC, jl_symbol("typeinf_code"), ct->world_age);
522522
fargs[2] = (jl_value_t*)mi;
523523
fargs[3] = jl_true;
524524
ci = (jl_code_info_t*)jl_apply(fargs, 4);

src/init.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NOTSAFEPOINT_ENTER
249249
if (jl_base_module) {
250250
size_t last_age = ct->world_age;
251251
ct->world_age = jl_get_world_counter();
252-
jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_atexit"));
252+
jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_atexit"), ct->world_age);
253253
if (f != NULL) {
254254
jl_value_t **fargs;
255255
JL_GC_PUSHARGS(fargs, 2);
@@ -357,7 +357,7 @@ JL_DLLEXPORT void jl_postoutput_hook(void)
357357
jl_task_t *ct = jl_get_current_task();
358358
size_t last_age = ct->world_age;
359359
ct->world_age = jl_get_world_counter();
360-
jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_postoutput"));
360+
jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_postoutput"), ct->world_age);
361361
if (f != NULL) {
362362
JL_TRY {
363363
JL_GC_PUSH1(&f);

src/interpreter.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,18 +162,18 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state
162162
}
163163

164164
// get the global (throwing if null) in the current world
165-
jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e)
165+
jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e, size_t world)
166166
{
167-
jl_value_t *v = jl_get_global_value(m, e);
167+
jl_value_t *v = jl_get_global_value(m, e, world);
168168
if (v == NULL)
169169
jl_undefined_var_error(e, (jl_value_t*)m);
170170
return v;
171171
}
172172

173173
// get the global (throwing if null) in the current world, optimized
174-
jl_value_t *jl_eval_globalref(jl_globalref_t *g)
174+
jl_value_t *jl_eval_globalref(jl_globalref_t *g, size_t world)
175175
{
176-
jl_value_t *v = jl_get_globalref_value(g);
176+
jl_value_t *v = jl_get_globalref_value(g, world);
177177
if (v == NULL)
178178
jl_undefined_var_error(g->name, (jl_value_t*)g->mod);
179179
return v;
@@ -218,10 +218,10 @@ static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s)
218218
return jl_quotenode_value(e);
219219
}
220220
if (jl_is_globalref(e)) {
221-
return jl_eval_globalref((jl_globalref_t*)e);
221+
return jl_eval_globalref((jl_globalref_t*)e, jl_current_task->world_age);
222222
}
223223
if (jl_is_symbol(e)) { // bare symbols appear in toplevel exprs not wrapped in `thunk`
224-
return jl_eval_global_var(s->module, (jl_sym_t*)e);
224+
return jl_eval_global_var(s->module, (jl_sym_t*)e, jl_current_task->world_age);
225225
}
226226
if (jl_is_pinode(e)) {
227227
jl_value_t *val = eval_value(jl_fieldref_noalloc(e, 0), s);

src/jl_uv.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ static void jl_uv_call_close_callback(jl_value_t *val)
162162
JL_GC_PUSHARGS(args, 2); // val is "rooted" in the finalizer list only right now
163163
args[0] = jl_eval_global_var(
164164
jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module),
165-
jl_symbol("_uv_hook_close")); // topmod(typeof(val))._uv_hook_close
165+
jl_symbol("_uv_hook_close"),
166+
jl_current_task->world_age); // topmod(typeof(val))._uv_hook_close
166167
args[1] = val;
167168
jl_apply(args, 2); // TODO: wrap in try-catch?
168169
JL_GC_POP();

src/jlapi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ static NOINLINE int true_main(int argc, char *argv[])
955955
ct->world_age = jl_get_world_counter();
956956

957957
jl_function_t *start_client = jl_base_module ?
958-
(jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("_start")) : NULL;
958+
(jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("_start"), ct->world_age) : NULL;
959959

960960
if (start_client) {
961961
int ret = 1;

src/jltypes.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3287,6 +3287,7 @@ void jl_init_types(void) JL_GC_DISABLED
32873287
jl_perm_symsvec(3, "mod", "name", "binding"),
32883288
jl_svec(3, jl_module_type, jl_symbol_type, jl_binding_type),
32893289
jl_emptysvec, 0, 0, 3);
3290+
jl_globalref_type->name->mayinlinealloc = 0; // not at all worthwhile, since the only constructor returns a boxed object
32903291

32913292
jl_core_module = jl_new_module(jl_symbol("Core"), NULL);
32923293

src/julia.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,9 +2094,7 @@ JL_DLLEXPORT jl_value_t *jl_get_existing_strong_gf(jl_binding_t *b JL_PROPAGATES
20942094
JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import);
20952095
JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var);
20962096
JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr);
2097-
JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr);
20982097
JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var);
2099-
JL_DLLEXPORT jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var);
21002098
JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT);
21012099
JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT);
21022100
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);

0 commit comments

Comments
 (0)