Skip to content

Commit

Permalink
remove jl_f_kwinvoke builtin, reimplement in Julia
Browse files Browse the repository at this point in the history
This instantly grants total inference and inlining support, where
previously this was a completely opaque call!
  • Loading branch information
vtjnash committed Oct 13, 2022
1 parent e5d1a2f commit e0cda0d
Show file tree
Hide file tree
Showing 7 changed files with 18 additions and 53 deletions.
11 changes: 11 additions & 0 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ include("generator.jl")
include("reflection.jl")
include("options.jl")

# define invoke(f, T, args...; kwargs...), without kwargs wrapping
# to forward to invoke
function Core.kwcall(kwargs, ::typeof(invoke), f, T, args...)
@inline
# prepend kwargs and f to the invoked from the user
T = rewrap_unionall(Tuple{Any, Core.Typeof(f), (unwrap_unionall(T)::DataType).parameters...}, T)
return invoke(Core.kwcall, T, kwargs, f, args...)
end
# invoke does not have its own call cache, but kwcall for invoke does
typeof(invoke).name.mt.max_args = 3 # invoke, f, T, args...

# core operations & types
include("promotion.jl")
include("tuple.jl")
Expand Down
4 changes: 2 additions & 2 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,11 @@ include(m::Module, fname::String) = ccall(:jl_load_, Any, (Any, Any), m, fname)

eval(m::Module, @nospecialize(e)) = ccall(:jl_toplevel_eval_in, Any, (Any, Any), m, e)

# dispatch token indicating a kwarg (keyword sorter) call
function kwcall end
# deprecated internal functions:
kwfunc(@nospecialize(f)) = kwcall
kwftype(@nospecialize(t)) = typeof(kwcall)
kwcall(kwargs, ::typeof(invoke), f, T, args...) = kwinvoke(kwargs, invoke, f, T, args...)
# invoke(f, T, args...; kwargs...) = kwinvoke(kwargs, invoke, f, T, args...)

mutable struct Box
contents::Any
Expand Down
1 change: 0 additions & 1 deletion src/builtin_proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ DECLARE_BUILTIN(is);
DECLARE_BUILTIN(isa);
DECLARE_BUILTIN(isdefined);
DECLARE_BUILTIN(issubtype);
DECLARE_BUILTIN(kwinvoke);
DECLARE_BUILTIN(modifyfield);
DECLARE_BUILTIN(nfields);
DECLARE_BUILTIN(setfield);
Expand Down
45 changes: 0 additions & 45 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1359,50 +1359,6 @@ JL_CALLABLE(jl_f_invoke)
return res;
}

JL_CALLABLE(jl_f_kwinvoke)
{
JL_NARGSV(invoke, 3);
jl_value_t *kwargs = args[0];
// args[1] is `invoke` itself
jl_value_t *func = args[2];
jl_value_t *argtypes = args[3];
jl_value_t *kws = jl_kwcall_func;
JL_GC_PUSH1(&argtypes);
if (jl_is_tuple_type(argtypes)) {
// construct a tuple type for invoking a keyword sorter by putting the kw container type
// and the type of the function at the front.
size_t i, nt = jl_nparams(argtypes) + 2;
if (nt < jl_page_size/sizeof(jl_value_t*)) {
jl_value_t **types = (jl_value_t**)alloca(nt*sizeof(jl_value_t*));
types[0] = (jl_value_t*)jl_namedtuple_type;
types[1] = jl_is_type(func) ? (jl_value_t*)jl_wrap_Type(func) : jl_typeof(func);
for (i = 2; i < nt; i++)
types[i] = jl_tparam(argtypes, i - 2);
argtypes = (jl_value_t*)jl_apply_tuple_type_v(types, nt);
}
else {
jl_svec_t *types = jl_alloc_svec_uninit(nt);
JL_GC_PUSH1(&types);
jl_svecset(types, 0, jl_namedtuple_type);
jl_svecset(types, 1, jl_is_type(func) ? (jl_value_t*)jl_wrap_Type(func) : jl_typeof(func));
for (i = 2; i < nt; i++)
jl_svecset(types, i, jl_tparam(argtypes, i - 2));
argtypes = (jl_value_t*)jl_apply_tuple_type(types);
JL_GC_POP();
}
}
else {
// invoke will throw an error
}
args[0] = kws;
args[1] = argtypes;
args[2] = kwargs;
args[3] = func;
jl_value_t *res = jl_f_invoke(NULL, args, nargs);
JL_GC_POP();
return res;
}

// Expr constructor for internal use ------------------------------------------

jl_expr_t *jl_exprn(jl_sym_t *head, size_t n)
Expand Down Expand Up @@ -2011,7 +1967,6 @@ void jl_init_primitives(void) JL_GC_DISABLED
// method table utils
jl_builtin_applicable = add_builtin_func("applicable", jl_f_applicable);
jl_builtin_invoke = add_builtin_func("invoke", jl_f_invoke);
jl_builtin_kwinvoke = add_builtin_func("kwinvoke", jl_f_kwinvoke);

// internal functions
jl_builtin_apply_type = add_builtin_func("apply_type", jl_f_apply_type);
Expand Down
1 change: 0 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1169,7 +1169,6 @@ static const auto &builtin_func_map() {
{ jl_f_svec_addr, new JuliaFunction{XSTR(jl_f_svec), get_func_sig, get_func_attrs} },
{ jl_f_applicable_addr, new JuliaFunction{XSTR(jl_f_applicable), get_func_sig, get_func_attrs} },
{ jl_f_invoke_addr, new JuliaFunction{XSTR(jl_f_invoke), get_func_sig, get_func_attrs} },
{ jl_f_kwinvoke_addr, new JuliaFunction{XSTR(jl_f_kwinvoke), get_func_sig, get_func_attrs} },
{ jl_f_isdefined_addr, new JuliaFunction{XSTR(jl_f_isdefined), get_func_sig, get_func_attrs} },
{ jl_f_getfield_addr, new JuliaFunction{XSTR(jl_f_getfield), get_func_sig, get_func_attrs} },
{ jl_f_setfield_addr, new JuliaFunction{XSTR(jl_f_setfield), get_func_sig, get_func_attrs} },
Expand Down
5 changes: 2 additions & 3 deletions src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ extern "C" {
// TODO: put WeakRefs on the weak_refs list during deserialization
// TODO: handle finalizers

#define NUM_TAGS 159
#define NUM_TAGS 157

// An array of references that need to be restored from the sysimg
// This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C.
Expand Down Expand Up @@ -251,7 +251,6 @@ jl_value_t **const*const get_tags(void) {
INSERT_TAG(jl_builtin_apply_type);
INSERT_TAG(jl_builtin_applicable);
INSERT_TAG(jl_builtin_invoke);
INSERT_TAG(jl_builtin_kwinvoke);
INSERT_TAG(jl_builtin__expr);
INSERT_TAG(jl_builtin_ifelse);
INSERT_TAG(jl_builtin__typebody);
Expand Down Expand Up @@ -312,7 +311,7 @@ static const jl_fptr_args_t id_to_fptrs[] = {
&jl_f_throw, &jl_f_is, &jl_f_typeof, &jl_f_issubtype, &jl_f_isa,
&jl_f_typeassert, &jl_f__apply_iterate, &jl_f__apply_pure,
&jl_f__call_latest, &jl_f__call_in_world, &jl_f__call_in_world_total, &jl_f_isdefined,
&jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call, &jl_f_kwinvoke,
&jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call,
&jl_f_getfield, &jl_f_setfield, &jl_f_swapfield, &jl_f_modifyfield,
&jl_f_replacefield, &jl_f_fieldtype, &jl_f_nfields,
&jl_f_arrayref, &jl_f_const_arrayref, &jl_f_arrayset, &jl_f_arraysize, &jl_f_apply_type,
Expand Down
4 changes: 3 additions & 1 deletion test/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,13 @@ sum3(A) = reduce(plus, A)
sum4(itr) = invoke(reduce, Tuple{Function, Any}, plus, itr)
sum5(A) = reduce(plus, A; init=0)
sum6(itr) = invoke(Core.kwcall, Tuple{NamedTuple{(:init,), Tuple{Int}}, typeof(reduce), Function, Any}, (init=0,), reduce, plus, itr)
sum61(itr) = invoke(reduce, Tuple{Function, Any}, init=0, plus, itr)
sum7(A) = mapreduce(x->x, plus, A)
sum8(itr) = invoke(mapreduce, Tuple{Function, Function, Any}, x->x, plus, itr)
sum9(A) = mapreduce(x->x, plus, A; init=0)
sum10(itr) = invoke(Core.kwcall, Tuple{NamedTuple{(:init,),Tuple{Int}}, typeof(mapreduce), Function, Function, Any}, (init=0,), mapreduce, x->x, plus, itr)
for f in (sum2, sum5, sum6, sum9, sum10)
sum11(itr) = invoke(mapreduce, Tuple{Function, Function, Any}, init=0, x->x, plus, itr)
for f in (sum2, sum5, sum6, sum61, sum9, sum10, sum11)
@test sum(z) == f(z)
@test sum(Int[]) == f(Int[]) == 0
@test sum(Int[7]) == f(Int[7]) == 7
Expand Down

0 comments on commit e0cda0d

Please sign in to comment.