Skip to content

Commit 2e322be

Browse files
committed
optimize invokelatest call performance (#38835)
Applications typically shouldn't use this function in performance sensitive places, as it hints that their design is flawed, but might as well make it faster anyways. and optimize invokelatest kwcall too, while we are at it (cherry picked from commit 2ff110b)
1 parent c74bc14 commit 2e322be

File tree

8 files changed

+31
-33
lines changed

8 files changed

+31
-33
lines changed

base/essentials.jl

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -703,12 +703,11 @@ call obsolete versions of a function `f`.
703703
`f` directly, and the type of the result cannot be inferred by the compiler.)
704704
"""
705705
function invokelatest(@nospecialize(f), @nospecialize args...; kwargs...)
706+
kwargs = Base.merge(NamedTuple(), kwargs)
706707
if isempty(kwargs)
707-
return Core._apply_latest(f, args)
708+
return Core._call_latest(f, args...)
708709
end
709-
# We use a closure (`inner`) to handle kwargs.
710-
inner() = f(args...; kwargs...)
711-
Core._apply_latest(inner)
710+
return Core._call_latest(Core.kwfunc(f), kwargs, f, args...)
712711
end
713712

714713
"""
@@ -738,11 +737,11 @@ of [`invokelatest`](@ref).
738737
world age refers to system state unrelated to the main Julia session.
739738
"""
740739
function invoke_in_world(world::UInt, @nospecialize(f), @nospecialize args...; kwargs...)
740+
kwargs = Base.merge(NamedTuple(), kwargs)
741741
if isempty(kwargs)
742-
return Core._apply_in_world(world, f, args)
742+
return Core._call_in_world(world, f, args...)
743743
end
744-
inner() = f(args...; kwargs...)
745-
Core._apply_in_world(world, inner)
744+
return Core._call_in_world(world, Core.kwfunc(f), kwargs, f, args...)
746745
end
747746

748747
# TODO: possibly make this an intrinsic

src/builtin_proto.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ DECLARE_BUILTIN(throw); DECLARE_BUILTIN(is);
2323
DECLARE_BUILTIN(typeof); DECLARE_BUILTIN(sizeof);
2424
DECLARE_BUILTIN(issubtype); DECLARE_BUILTIN(isa);
2525
DECLARE_BUILTIN(_apply); DECLARE_BUILTIN(_apply_pure);
26-
DECLARE_BUILTIN(_apply_latest); DECLARE_BUILTIN(_apply_iterate);
27-
DECLARE_BUILTIN(_apply_in_world);
26+
DECLARE_BUILTIN(_call_latest); DECLARE_BUILTIN(_apply_iterate);
27+
DECLARE_BUILTIN(_call_in_world);
2828
DECLARE_BUILTIN(isdefined); DECLARE_BUILTIN(nfields);
2929
DECLARE_BUILTIN(tuple); DECLARE_BUILTIN(svec);
3030
DECLARE_BUILTIN(getfield); DECLARE_BUILTIN(setfield);

src/builtins.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -712,32 +712,31 @@ JL_CALLABLE(jl_f__apply_pure)
712712
return ret;
713713
}
714714

715-
// this is like `_apply`, but always runs in the newest world
716-
JL_CALLABLE(jl_f__apply_latest)
715+
// this is like a regular call, but always runs in the newest world
716+
JL_CALLABLE(jl_f__call_latest)
717717
{
718718
jl_ptls_t ptls = jl_get_ptls_states();
719719
size_t last_age = ptls->world_age;
720720
if (!ptls->in_pure_callback)
721721
ptls->world_age = jl_world_counter;
722-
jl_value_t *ret = jl_f__apply(NULL, args, nargs);
722+
jl_value_t *ret = jl_apply(args, nargs);
723723
ptls->world_age = last_age;
724724
return ret;
725725
}
726726

727-
// Like `_apply`, but runs in the specified world.
727+
// Like call_in_world, but runs in the specified world.
728728
// If world > jl_world_counter, run in the latest world.
729-
JL_CALLABLE(jl_f__apply_in_world)
729+
JL_CALLABLE(jl_f__call_in_world)
730730
{
731731
JL_NARGSV(_apply_in_world, 2);
732732
jl_ptls_t ptls = jl_get_ptls_states();
733733
size_t last_age = ptls->world_age;
734734
JL_TYPECHK(_apply_in_world, ulong, args[0]);
735735
size_t world = jl_unbox_ulong(args[0]);
736736
world = world <= jl_world_counter ? world : jl_world_counter;
737-
if (!ptls->in_pure_callback) {
737+
if (!ptls->in_pure_callback)
738738
ptls->world_age = world;
739-
}
740-
jl_value_t *ret = do_apply(NULL, args+1, nargs-1, NULL);
739+
jl_value_t *ret = jl_apply(&args[1], nargs - 1);
741740
ptls->world_age = last_age;
742741
return ret;
743742
}
@@ -1555,8 +1554,8 @@ void jl_init_primitives(void) JL_GC_DISABLED
15551554
jl_builtin__expr = add_builtin_func("_expr", jl_f__expr);
15561555
jl_builtin_svec = add_builtin_func("svec", jl_f_svec);
15571556
add_builtin_func("_apply_pure", jl_f__apply_pure);
1558-
add_builtin_func("_apply_latest", jl_f__apply_latest);
1559-
add_builtin_func("_apply_in_world", jl_f__apply_in_world);
1557+
add_builtin_func("_call_latest", jl_f__call_latest);
1558+
add_builtin_func("_call_in_world", jl_f__call_in_world);
15601559
add_builtin_func("_typevar", jl_f__typevar);
15611560
add_builtin_func("_structtype", jl_f__structtype);
15621561
add_builtin_func("_abstracttype", jl_f__abstracttype);

src/codegen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -841,8 +841,8 @@ static const std::map<jl_fptr_args_t, JuliaFunction*> builtin_func_map = {
841841
{ &jl_f__apply, new JuliaFunction{"jl_f__apply", get_func_sig, get_func_attrs} },
842842
{ &jl_f__apply_iterate, new JuliaFunction{"jl_f__apply_iterate", get_func_sig, get_func_attrs} },
843843
{ &jl_f__apply_pure, new JuliaFunction{"jl_f__apply_pure", get_func_sig, get_func_attrs} },
844-
{ &jl_f__apply_latest, new JuliaFunction{"jl_f__apply_latest", get_func_sig, get_func_attrs} },
845-
{ &jl_f__apply_in_world, new JuliaFunction{"jl_f__apply_in_world", get_func_sig, get_func_attrs} },
844+
{ &jl_f__call_latest, new JuliaFunction{"jl_f__call_latest", get_func_sig, get_func_attrs} },
845+
{ &jl_f__call_in_world, new JuliaFunction{"jl_f__call_in_world", get_func_sig, get_func_attrs} },
846846
{ &jl_f_throw, new JuliaFunction{"jl_f_throw", get_func_sig, get_func_attrs} },
847847
{ &jl_f_tuple, jltuple_func },
848848
{ &jl_f_svec, new JuliaFunction{"jl_f_svec", get_func_sig, get_func_attrs} },

src/jl_exported_funcs.inc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,12 @@
177177
XX(jl_expand_with_loc_warn) \
178178
XX(jl_extern_c) \
179179
XX(jl_f__abstracttype) \
180-
XX(jl_f_applicable) \
181180
XX(jl_f__apply) \
182-
XX(jl_f__apply_in_world) \
183181
XX(jl_f__apply_iterate) \
184-
XX(jl_f__apply_latest) \
185182
XX(jl_f__apply_pure) \
183+
XX(jl_f__call_in_world) \
184+
XX(jl_f__call_latest) \
185+
XX(jl_f_applicable) \
186186
XX(jl_f_apply_type) \
187187
XX(jl_f_arrayref) \
188188
XX(jl_f_arrayset) \

src/jlfrontend.scm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,11 @@
191191
(= (call include ,x)
192192
(block
193193
,@loc
194-
(call (core _apply_latest) (top include) (call (core svec) ,name ,x))))
194+
(call (core _call_latest) (top include) ,name ,x)))
195195
(= (call include (:: ,mex (top Function)) ,x)
196196
(block
197197
,@loc
198-
(call (core _apply_latest) (top include) (call (core svec) ,mex ,name ,x))))))
198+
(call (core _call_latest) (top include) ,mex ,name ,x)))))
199199
'none 0))
200200

201201
; run whole frontend on a string. useful for testing.

src/staticdata.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ void *native_functions;
237237
static const jl_fptr_args_t id_to_fptrs[] = {
238238
&jl_f_throw, &jl_f_is, &jl_f_typeof, &jl_f_issubtype, &jl_f_isa,
239239
&jl_f_typeassert, &jl_f__apply, &jl_f__apply_iterate, &jl_f__apply_pure,
240-
&jl_f__apply_latest, &jl_f__apply_in_world, &jl_f_isdefined,
240+
&jl_f__call_latest, &jl_f__call_in_world, &jl_f_isdefined,
241241
&jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call, &jl_f_invoke_kwsorter,
242242
&jl_f_getfield, &jl_f_setfield, &jl_f_fieldtype, &jl_f_nfields,
243243
&jl_f_arrayref, &jl_f_const_arrayref, &jl_f_arrayset, &jl_f_arraysize, &jl_f_apply_type,

test/cmdlineargs.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,15 +317,15 @@ let exename = `$(Base.julia_cmd()) --startup-file=no`
317317
@test popfirst!(got) == " 80 []"
318318
if Sys.WORD_SIZE == 64
319319
# P64 pools with 64 bit tags
320-
@test popfirst!(got) == " 32 Base.invokelatest(g, 0)"
321-
@test popfirst!(got) == " 48 Base.invokelatest(g, x)"
320+
@test popfirst!(got) == " 16 Base.invokelatest(g, 0)"
321+
@test popfirst!(got) == " 32 Base.invokelatest(g, x)"
322322
elseif 12 == (() -> @allocated ccall(:jl_gc_allocobj, Ptr{Cvoid}, (Csize_t,), 8))()
323323
# See if we have a 12-byte pool with 32 bit tags (MAX_ALIGN = 4)
324-
@test popfirst!(got) == " 24 Base.invokelatest(g, 0)"
325-
@test popfirst!(got) == " 36 Base.invokelatest(g, x)"
324+
@test popfirst!(got) == " 12 Base.invokelatest(g, 0)"
325+
@test popfirst!(got) == " 24 Base.invokelatest(g, x)"
326326
else # MAX_ALIGN >= 8
327-
@test popfirst!(got) == " 16 Base.invokelatest(g, 0)"
328-
@test popfirst!(got) == " 48 Base.invokelatest(g, x)"
327+
@test popfirst!(got) == " 8 Base.invokelatest(g, 0)"
328+
@test popfirst!(got) == " 32 Base.invokelatest(g, x)"
329329
end
330330
@test popfirst!(got) == " 80 []"
331331
@test popfirst!(got) == " - end"

0 commit comments

Comments
 (0)