Skip to content

Commit 8d78db7

Browse files
authored
add the ability to specify the external name of a ccallable (#57763)
This will allow exporting julia `main` as something else so a separate native `main` can be written to handle initialization. I'm sure it will have lots of other uses too though.
2 parents e78cf6c + f2a83bf commit 8d78db7

File tree

13 files changed

+61
-46
lines changed

13 files changed

+61
-46
lines changed

Compiler/src/typeinfer.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,8 +1371,7 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim_m
13711371
end
13721372
# additionally enqueue the ccallable entrypoint / adapter, which implicitly
13731373
# invokes the above ci
1374-
push!(codeinfos, rt)
1375-
push!(codeinfos, sig)
1374+
push!(codeinfos, item)
13761375
end
13771376
end
13781377
while !isempty(tocompile)

Compiler/src/verifytrim.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ function get_verify_typeinf_trim(codeinfos::Vector{Any})
256256
caches = IdDict{MethodInstance,CodeInstance}()
257257
errors = ErrorList()
258258
parents = ParentMap()
259-
for i = 1:2:length(codeinfos)
259+
for i = 1:length(codeinfos)
260260
item = codeinfos[i]
261261
if item isa CodeInstance
262262
push!(inspected, item)
@@ -268,14 +268,14 @@ function get_verify_typeinf_trim(codeinfos::Vector{Any})
268268
end
269269
end
270270
end
271-
for i = 1:2:length(codeinfos)
271+
for i = 1:length(codeinfos)
272272
item = codeinfos[i]
273273
if item isa CodeInstance
274274
src = codeinfos[i + 1]::CodeInfo
275275
verify_codeinstance!(item, src, inspected, caches, parents, errors)
276-
else
277-
rt = item::Type
278-
sig = codeinfos[i + 1]::Type
276+
elseif item isa SimpleVector
277+
rt = item[1]::Type
278+
sig = item[2]::Type
279279
ptr = ccall(:jl_get_specialization1,
280280
#= MethodInstance =# Ptr{Cvoid}, (Any, Csize_t, Cint),
281281
sig, this_world, #= mt_cache =# 0)

Compiler/test/verifytrim.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ let infos = typeinf_ext_toplevel(Any[Core.svec(Base.SecretBuffer, Tuple{Type{Bas
4444
4545
$""", repr)
4646

47-
resize!(infos, 2)
48-
@test infos[1] isa Type && infos[2] isa Type
47+
resize!(infos, 1)
48+
@test infos[1] isa Core.SimpleVector && infos[1][1] isa Type && infos[1][2] isa Type
4949
errors, parents = get_verify_typeinf_trim(infos)
5050
desc = only(errors)
5151
@test !desc.first

base/c.jl

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,11 @@ function exit_on_sigint(on::Bool)
203203
ccall(:jl_exit_on_sigint, Cvoid, (Cint,), on)
204204
end
205205

206-
function _ccallable(rt::Type, sigt::Type)
207-
ccall(:jl_extern_c, Cvoid, (Any, Any), rt, sigt)
206+
function _ccallable(name::Union{Nothing, String}, rt::Type, sigt::Type)
207+
ccall(:jl_extern_c, Cvoid, (Any, Any, Any), name, rt, sigt)
208208
end
209209

210-
function expand_ccallable(rt, def)
210+
function expand_ccallable(name, rt, def)
211211
if isa(def,Expr) && (def.head === :(=) || def.head === :function)
212212
sig = def.args[1]
213213
if sig.head === :(::)
@@ -235,24 +235,30 @@ function expand_ccallable(rt, def)
235235
end
236236
return quote
237237
@__doc__ $(esc(def))
238-
_ccallable($(esc(rt)), $(Expr(:curly, :Tuple, esc(f), map(esc, at)...)))
238+
_ccallable($name, $(esc(rt)), $(Expr(:curly, :Tuple, esc(f), map(esc, at)...)))
239239
end
240240
end
241241
end
242242
error("expected method definition in @ccallable")
243243
end
244244

245245
"""
246-
@ccallable(def)
246+
@ccallable ["name"] function f(...)::RetType ... end
247247
248248
Make the annotated function be callable from C using its name. This can, for example,
249-
be used to expose functionality as a C-API when creating a custom Julia sysimage.
249+
be used to expose functionality as a C API when creating a custom Julia sysimage.
250+
251+
If the first argument is a string, it is used as the external name of the function.
250252
"""
251253
macro ccallable(def)
252-
expand_ccallable(nothing, def)
254+
expand_ccallable(nothing, nothing, def)
253255
end
254256
macro ccallable(rt, def)
255-
expand_ccallable(rt, def)
257+
if rt isa String
258+
expand_ccallable(rt, nothing, def)
259+
else
260+
expand_ccallable(nothing, rt, def)
261+
end
256262
end
257263

258264
# @ccall implementation

src/aotcompile.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -784,9 +784,12 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvm
784784
compiled_functions[codeinst] = {std::move(result_m), std::move(decls)};
785785
}
786786
else {
787-
jl_value_t *sig = jl_array_ptr_ref(codeinfos, ++i);
788-
assert(jl_is_type(item) && jl_is_type(sig));
789-
jl_generate_ccallable(clone.getModuleUnlocked(), nullptr, item, sig, params);
787+
assert(jl_is_simplevector(item));
788+
jl_value_t *rt = jl_svecref(item, 0);
789+
jl_value_t *sig = jl_svecref(item, 1);
790+
jl_value_t *nameval = jl_svec_len(item) == 2 ? jl_nothing : jl_svecref(item, 2);
791+
assert(jl_is_type(rt) && jl_is_type(sig));
792+
jl_generate_ccallable(clone.getModuleUnlocked(), nameval, rt, sig, params);
790793
}
791794
}
792795
// finally, make sure all referenced methods get fixed up, particularly if the user declined to compile them

src/codegen-stubs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ JL_DLLEXPORT uint32_t jl_get_LLVM_VERSION_fallback(void)
7070
return 0;
7171
}
7272

73-
JL_DLLEXPORT int jl_compile_extern_c_fallback(LLVMOrcThreadSafeModuleRef llvmmod, void *params, void *sysimg, jl_value_t *declrt, jl_value_t *sigt)
73+
JL_DLLEXPORT int jl_compile_extern_c_fallback(LLVMOrcThreadSafeModuleRef llvmmod, void *params, void *sysimg, jl_value_t *name, jl_value_t *declrt, jl_value_t *sigt)
7474
{
7575
// Assume we were able to register the ccallable with the JIT. The
7676
// fact that we didn't is not observable since we cannot compile

src/codegen.cpp

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7709,14 +7709,14 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con
77097709

77107710
// do codegen to create a C-callable alias/wrapper, or if sysimg_handle is set,
77117711
// restore one from a loaded system image.
7712-
const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t &params)
7712+
const char *jl_generate_ccallable(Module *llvmmod, jl_value_t *nameval, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t &params)
77137713
{
77147714
++GeneratedCCallables;
77157715
jl_datatype_t *ft = (jl_datatype_t*)jl_tparam0(sigt);
77167716
assert(jl_is_datatype(ft));
77177717
jl_value_t *ff = ft->instance;
77187718
assert(ff);
7719-
const char *name = jl_symbol_name(ft->name->mt->name);
7719+
const char *name = !jl_is_string(nameval) ? jl_symbol_name(ft->name->mt->name) : jl_string_data(nameval);
77207720
jl_value_t *crt = declrt;
77217721
if (jl_is_abstract_ref_type(declrt)) {
77227722
declrt = jl_tparam0(declrt);
@@ -7738,25 +7738,12 @@ const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value
77387738
function_sig_t sig("cfunction", lcrt, crt, toboxed, false,
77397739
argtypes, NULL, false, CallingConv::C, false, &params);
77407740
if (sig.err_msg.empty()) {
7741-
if (sysimg_handle) {
7742-
// restore a ccallable from the system image
7743-
void *addr;
7744-
int found = jl_dlsym(sysimg_handle, name, &addr, 0);
7745-
if (found)
7746-
add_named_global(name, addr);
7747-
else {
7748-
err = jl_get_exceptionf(jl_errorexception_type, "%s not found in sysimg", name);
7749-
jl_throw(err);
7750-
}
7751-
}
7752-
else {
7753-
//Safe b/c params holds context lock
7754-
Function *cw = gen_cfun_wrapper(llvmmod, params, sig, ff, name, declrt, sigt, NULL, NULL, NULL);
7755-
auto alias = GlobalAlias::create(cw->getValueType(), cw->getType()->getAddressSpace(),
7756-
GlobalValue::ExternalLinkage, name, cw, llvmmod);
7757-
if (params.TargetTriple.isOSBinFormatCOFF()) {
7758-
alias->setDLLStorageClass(GlobalValue::DLLStorageClassTypes::DLLExportStorageClass);
7759-
}
7741+
//Safe b/c params holds context lock
7742+
Function *cw = gen_cfun_wrapper(llvmmod, params, sig, ff, name, declrt, sigt, NULL, NULL, NULL);
7743+
auto alias = GlobalAlias::create(cw->getValueType(), cw->getType()->getAddressSpace(),
7744+
GlobalValue::ExternalLinkage, name, cw, llvmmod);
7745+
if (params.TargetTriple.isOSBinFormatCOFF()) {
7746+
alias->setDLLStorageClass(GlobalValue::DLLStorageClassTypes::DLLExportStorageClass);
77607747
}
77617748
JL_GC_POP();
77627749
return name;

src/gf.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4596,7 +4596,7 @@ JL_DLLEXPORT void jl_typeinf_timing_end(uint64_t start, int is_recompile)
45964596
}
45974597

45984598
// declare a C-callable entry point; called during code loading from the toplevel
4599-
JL_DLLEXPORT void jl_extern_c(jl_value_t *declrt, jl_tupletype_t *sigt)
4599+
JL_DLLEXPORT void jl_extern_c(jl_value_t *name, jl_value_t *declrt, jl_tupletype_t *sigt)
46004600
{
46014601
// validate arguments. try to do as many checks as possible here to avoid
46024602
// throwing errors later during codegen.
@@ -4627,7 +4627,10 @@ JL_DLLEXPORT void jl_extern_c(jl_value_t *declrt, jl_tupletype_t *sigt)
46274627
if (!jl_is_method(meth))
46284628
jl_error("@ccallable: could not find requested method");
46294629
JL_GC_PUSH1(&meth);
4630-
meth->ccallable = jl_svec2(declrt, (jl_value_t*)sigt);
4630+
if (name == jl_nothing)
4631+
meth->ccallable = jl_svec2(declrt, (jl_value_t*)sigt);
4632+
else
4633+
meth->ccallable = jl_svec3(declrt, (jl_value_t*)sigt, name);
46314634
jl_gc_wb(meth, meth->ccallable);
46324635
JL_GC_POP();
46334636
}

src/jitlayers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ struct jl_codegen_params_t {
284284
~jl_codegen_params_t() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE = default;
285285
};
286286

287-
const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t &params);
287+
const char *jl_generate_ccallable(Module *llvmmod, jl_value_t *nameval, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t &params);
288288

289289
jl_llvm_functions_t jl_emit_code(
290290
orc::ThreadSafeModule &M,

src/julia.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,6 +1925,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_new_method_instance_uninit(void);
19251925
JL_DLLEXPORT jl_svec_t *jl_svec(size_t n, ...) JL_MAYBE_UNROOTED;
19261926
JL_DLLEXPORT jl_svec_t *jl_svec1(void *a);
19271927
JL_DLLEXPORT jl_svec_t *jl_svec2(void *a, void *b);
1928+
JL_DLLEXPORT jl_svec_t *jl_svec3(void *a, void *b, void *c);
19281929
JL_DLLEXPORT jl_svec_t *jl_alloc_svec(size_t n);
19291930
JL_DLLEXPORT jl_svec_t *jl_alloc_svec_uninit(size_t n);
19301931
JL_DLLEXPORT jl_svec_t *jl_svec_copy(jl_svec_t *a);

0 commit comments

Comments
 (0)