Skip to content

Commit

Permalink
staticdata: remove reinit_ccallable
Browse files Browse the repository at this point in the history
This commit removes `jl_reinit_ccallable` whose purpose is unclear.
Specifically, the function re-adds C-callable functions to the execution
engine during the loading of sysimages/pkgimages, but the consensus is
that the function is largely unnecessary because `ccall` can find
symbols via `dlsym`. The function's only apparent use case is a
contrived `llvmcall` example, only because we currently don't add the
sysimage symbols to the JIT, but we could do anyway. `llvmcall` has
always been experimental, and if it is truly needed, the functionality
for finding the symbols should be properly implemented later.
  • Loading branch information
aviatesk committed Jan 15, 2025
1 parent 6cf2b14 commit 9a5ac56
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 262 deletions.
2 changes: 1 addition & 1 deletion src/aotcompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvm
else {
jl_value_t *sig = jl_array_ptr_ref(codeinfos, ++i);
assert(jl_is_type(item) && jl_is_type(sig));
jl_compile_extern_c(wrap(&clone), &params, NULL, item, sig);
jl_generate_ccallable(clone.getModuleUnlocked(), nullptr, item, sig, params);
}
}
// finally, make sure all referenced methods get fixed up, particularly if the user declined to compile them
Expand Down
1 change: 0 additions & 1 deletion src/codegen-stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ JL_DLLEXPORT void jl_get_llvm_gvs_fallback(void *native_code, arraylist_t *gvs)
JL_DLLEXPORT void jl_get_llvm_external_fns_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE
JL_DLLEXPORT void jl_get_llvm_mis_fallback(void *native_code, arraylist_t* MIs) UNAVAILABLE

JL_DLLEXPORT void jl_extern_c_fallback(jl_function_t *f, jl_value_t *rt, jl_value_t *argt, char *name) UNAVAILABLE
JL_DLLEXPORT jl_value_t *jl_dump_method_asm_fallback(jl_method_instance_t *linfo, size_t world,
char emit_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary) UNAVAILABLE
JL_DLLEXPORT jl_value_t *jl_dump_function_ir_fallback(jl_llvmf_dump_t *dump, char strip_ir_metadata, char dump_module, const char *debuginfo) UNAVAILABLE
Expand Down
38 changes: 38 additions & 0 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -4607,6 +4607,44 @@ JL_DLLEXPORT void jl_typeinf_timing_end(uint64_t start, int is_recompile)
}
}

// declare a C-callable entry point; called during code loading from the toplevel
JL_DLLEXPORT void jl_extern_c(jl_value_t *declrt, jl_tupletype_t *sigt)
{
// validate arguments. try to do as many checks as possible here to avoid
// throwing errors later during codegen.
JL_TYPECHK(@ccallable, type, declrt);
if (!jl_is_tuple_type(sigt))
jl_type_error("@ccallable", (jl_value_t*)jl_anytuple_type_type, (jl_value_t*)sigt);
// check that f is a guaranteed singleton type
jl_datatype_t *ft = (jl_datatype_t*)jl_tparam0(sigt);
if (!jl_is_datatype(ft) || !jl_is_datatype_singleton(ft))
jl_error("@ccallable: function object must be a singleton");

// compute / validate return type
if (!jl_is_concrete_type(declrt) || jl_is_kind(declrt))
jl_error("@ccallable: return type must be concrete and correspond to a C type");
if (!jl_type_mappable_to_c(declrt))
jl_error("@ccallable: return type doesn't correspond to a C type");

// validate method signature
size_t i, nargs = jl_nparams(sigt);
for (i = 1; i < nargs; i++) {
jl_value_t *ati = jl_tparam(sigt, i);
if (!jl_is_concrete_type(ati) || jl_is_kind(ati) || !jl_type_mappable_to_c(ati))
jl_error("@ccallable: argument types must be concrete");
}

// save a record of this so that the alias is generated when we write an object file
jl_method_t *meth = (jl_method_t*)jl_methtable_lookup(ft->name->mt, (jl_value_t*)sigt, jl_atomic_load_acquire(&jl_world_counter));
if (!jl_is_method(meth))
jl_error("@ccallable: could not find requested method");
JL_GC_PUSH1(&meth);
meth->ccallable = jl_svec2(declrt, (jl_value_t*)sigt);
jl_gc_wb(meth, meth->ccallable);
JL_GC_POP();
}


#ifdef __cplusplus
}
#endif
134 changes: 0 additions & 134 deletions src/jitlayers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,140 +770,6 @@ void jl_emit_codeinst_to_jit_impl(
}


const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t &params);

// compile a C-callable alias
extern "C" JL_DLLEXPORT_CODEGEN
int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void *sysimg, jl_value_t *declrt, jl_value_t *sigt)
{
auto ct = jl_current_task;
bool timed = (ct->reentrant_timing & 1) == 0;
if (timed)
ct->reentrant_timing |= 1;
uint64_t compiler_start_time = 0;
uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
if (measure_compile_time_enabled)
compiler_start_time = jl_hrtime();
jl_codegen_params_t *pparams = (jl_codegen_params_t*)p;
DataLayout DL = pparams ? pparams->DL : jl_ExecutionEngine->getDataLayout();
Triple TargetTriple = pparams ? pparams->TargetTriple : jl_ExecutionEngine->getTargetTriple();
orc::ThreadSafeContext ctx;
auto into = unwrap(llvmmod);
orc::ThreadSafeModule backing;
bool success = true;
const char *name = "";
if (into == NULL) {
ctx = pparams ? pparams->tsctx : jl_ExecutionEngine->makeContext();
backing = jl_create_ts_module("cextern", ctx, DL, TargetTriple);
into = &backing;
}
{ // params scope
jl_codegen_params_t params(into->getContext(), DL, TargetTriple);
if (pparams == NULL) {
params.cache = p == NULL;
params.imaging_mode = 0;
params.tsctx.getContext()->setDiscardValueNames(true);
pparams = &params;
}
Module &M = *into->getModuleUnlocked();
assert(pparams->tsctx.getContext() == &M.getContext());
name = jl_generate_ccallable(&M, sysimg, declrt, sigt, *pparams);
if (!sysimg && !p) {
{ // drop lock to keep analyzer happy (since it doesn't know we have the only reference to it)
auto release = std::move(params.tsctx_lock);
}
{ // lock scope
jl_unique_gcsafe_lock lock(extern_c_lock);
if (jl_ExecutionEngine->getGlobalValueAddress(name))
success = false;
}
params.tsctx_lock = params.tsctx.getLock(); // re-acquire lock
if (success && params.cache) {
size_t newest_world = jl_atomic_load_acquire(&jl_world_counter);
for (auto &it : params.workqueue) { // really just zero or one, and just the ABI not the rest of the metadata
jl_code_instance_t *codeinst = it.first;
JL_GC_PROMISE_ROOTED(codeinst);
jl_code_instance_t *newest_ci = jl_type_infer(jl_get_ci_mi(codeinst), newest_world, SOURCE_MODE_ABI);
if (newest_ci) {
if (jl_egal(codeinst->rettype, newest_ci->rettype))
it.first = codeinst;
jl_compile_codeinst_now(newest_ci);
}
}
jl_analyze_workqueue(nullptr, params, true);
assert(params.workqueue.empty());
finish_params(&M, params);
}
}
pparams = nullptr;
}
if (!sysimg && success && llvmmod == NULL) {
{ // lock scope
jl_unique_gcsafe_lock lock(extern_c_lock);
if (!jl_ExecutionEngine->getGlobalValueAddress(name)) {
{
auto Lock = backing.getContext().getLock();
jl_ExecutionEngine->optimizeDLSyms(*backing.getModuleUnlocked()); // safepoint
}
jl_ExecutionEngine->addModule(std::move(backing));
success = jl_ExecutionEngine->getGlobalValueAddress(name);
assert(success);
}
}
}
if (timed) {
if (measure_compile_time_enabled) {
auto end = jl_hrtime();
jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, end - compiler_start_time);
}
ct->reentrant_timing &= ~1ull;
}
return success;
}

// declare a C-callable entry point; called during code loading from the toplevel
extern "C" JL_DLLEXPORT_CODEGEN
void jl_extern_c_impl(jl_value_t *declrt, jl_tupletype_t *sigt)
{
// validate arguments. try to do as many checks as possible here to avoid
// throwing errors later during codegen.
JL_TYPECHK(@ccallable, type, declrt);
if (!jl_is_tuple_type(sigt))
jl_type_error("@ccallable", (jl_value_t*)jl_anytuple_type_type, (jl_value_t*)sigt);
// check that f is a guaranteed singleton type
jl_datatype_t *ft = (jl_datatype_t*)jl_tparam0(sigt);
if (!jl_is_datatype(ft) || !jl_is_datatype_singleton(ft))
jl_error("@ccallable: function object must be a singleton");

// compute / validate return type
if (!jl_is_concrete_type(declrt) || jl_is_kind(declrt))
jl_error("@ccallable: return type must be concrete and correspond to a C type");
if (!jl_type_mappable_to_c(declrt))
jl_error("@ccallable: return type doesn't correspond to a C type");

// validate method signature
size_t i, nargs = jl_nparams(sigt);
for (i = 1; i < nargs; i++) {
jl_value_t *ati = jl_tparam(sigt, i);
if (!jl_is_concrete_type(ati) || jl_is_kind(ati) || !jl_type_mappable_to_c(ati))
jl_error("@ccallable: argument types must be concrete");
}

// save a record of this so that the alias is generated when we write an object file
jl_method_t *meth = (jl_method_t*)jl_methtable_lookup(ft->name->mt, (jl_value_t*)sigt, jl_atomic_load_acquire(&jl_world_counter));
if (!jl_is_method(meth))
jl_error("@ccallable: could not find requested method");
JL_GC_PUSH1(&meth);
meth->ccallable = jl_svec2(declrt, (jl_value_t*)sigt);
jl_gc_wb(meth, meth->ccallable);
JL_GC_POP();

// create the alias in the current runtime environment
int success = jl_compile_extern_c(NULL, NULL, NULL, declrt, (jl_value_t*)sigt);
if (!success)
jl_error("@ccallable was already defined for this method name");
}

extern "C" JL_DLLEXPORT_CODEGEN
int jl_compile_codeinst_impl(jl_code_instance_t *ci)
{
Expand Down
2 changes: 2 additions & 0 deletions src/jitlayers.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ struct jl_codegen_params_t {
~jl_codegen_params_t() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE = default;
};

const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t &params);

jl_llvm_functions_t jl_emit_code(
orc::ThreadSafeModule &M,
jl_method_instance_t *mi,
Expand Down
2 changes: 0 additions & 2 deletions src/jl_exported_funcs.inc
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,6 @@
YY(jl_dump_function_ir) \
YY(jl_dump_method_asm) \
YY(jl_emit_codeinst_to_jit) \
YY(jl_extern_c) \
YY(jl_get_llvmf_defn) \
YY(jl_get_llvm_function) \
YY(jl_get_llvm_module) \
Expand All @@ -534,7 +533,6 @@
YY(jl_register_fptrs) \
YY(jl_generate_fptr_for_unspecialized) \
YY(jl_compile_codeinst) \
YY(jl_compile_extern_c) \
YY(jl_teardown_codegen) \
YY(jl_jit_total_bytes) \
YY(jl_create_native) \
Expand Down
1 change: 0 additions & 1 deletion src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1959,7 +1959,6 @@ JL_DLLEXPORT uint32_t jl_crc32c(uint32_t crc, const char *buf, size_t len);

JL_DLLIMPORT void jl_generate_fptr_for_unspecialized(jl_code_instance_t *unspec);
JL_DLLIMPORT int jl_compile_codeinst(jl_code_instance_t *unspec);
JL_DLLIMPORT int jl_compile_extern_c(LLVMOrcThreadSafeModuleRef llvmmod, void *params, void *sysimg, jl_value_t *declrt, jl_value_t *sigt);
JL_DLLIMPORT void jl_emit_codeinst_to_jit(jl_code_instance_t *codeinst, jl_code_info_t *src);

typedef struct {
Expand Down
51 changes: 3 additions & 48 deletions src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
- step 3 combines the different sections (fields of `jl_serializer_state`) into one
- step 4 writes the values of the hard-coded tagged items and `ccallable_list`
Much of the "real work" during deserialization is done by `get_item_for_reloc`. But a few items require specific
attention:
- uniquing: during deserialization, the target item (an "external" type or MethodInstance) must be checked against
Expand Down Expand Up @@ -538,7 +536,6 @@ typedef struct {
arraylist_t uniquing_objs; // a list of locations that reference non-types that must be de-duplicated
arraylist_t fixup_types; // a list of locations of types requiring (re)caching
arraylist_t fixup_objs; // a list of locations of objects requiring (re)caching
arraylist_t ccallable_list; // @ccallable entry points to install
// mapping from a buildid_idx to a depmods_idx
jl_array_t *buildid_depmods_idxs;
// record of build_ids for all external linkages, in order of serialization for the current sysimg/pkgimg
Expand Down Expand Up @@ -1778,8 +1775,6 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED
else {
newm->nroots_sysimg = m->roots ? jl_array_len(m->roots) : 0;
}
if (m->ccallable)
arraylist_push(&s->ccallable_list, (void*)reloc_offset);
}
else if (jl_is_method_instance(v)) {
assert(f == s->s);
Expand Down Expand Up @@ -2456,29 +2451,6 @@ static void jl_root_new_gvars(jl_serializer_state *s, jl_image_t *image, uint32_
}
}


static void jl_compile_extern(jl_method_t *m, void *sysimg_handle) JL_GC_DISABLED
{
// install ccallable entry point in JIT
assert(m); // makes clang-sa happy
jl_svec_t *sv = m->ccallable;
int success = jl_compile_extern_c(NULL, NULL, sysimg_handle, jl_svecref(sv, 0), jl_svecref(sv, 1));
if (!success)
jl_safe_printf("WARNING: @ccallable was already defined for this method name\n"); // enjoy a very bad time
assert(success || !sysimg_handle);
}


static void jl_reinit_ccallable(arraylist_t *ccallable_list, char *base, void *sysimg_handle)
{
for (size_t i = 0; i < ccallable_list->len; i++) {
uintptr_t item = (uintptr_t)ccallable_list->items[i];
jl_method_t *m = (jl_method_t*)(base + item);
jl_compile_extern(m, sysimg_handle);
}
}


// Code below helps slim down the images by
// removing cached types not referenced in the stream
static jl_svec_t *jl_prune_type_cache_hash(jl_svec_t *cache) JL_GC_DISABLED
Expand Down Expand Up @@ -3007,7 +2979,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
arraylist_new(&s.uniquing_objs, 0);
arraylist_new(&s.fixup_types, 0);
arraylist_new(&s.fixup_objs, 0);
arraylist_new(&s.ccallable_list, 0);
s.buildid_depmods_idxs = image_to_depmodidx(mod_array);
s.link_ids_relocs = jl_alloc_array_1d(jl_array_int32_type, 0);
s.link_ids_gctags = jl_alloc_array_1d(jl_array_int32_type, 0);
Expand Down Expand Up @@ -3252,7 +3223,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
write_uint32(f, jl_array_len(s.link_ids_external_fnvars));
ios_write(f, (char*)jl_array_data(s.link_ids_external_fnvars, uint32_t), jl_array_len(s.link_ids_external_fnvars) * sizeof(uint32_t));
write_uint32(f, external_fns_begin);
jl_write_arraylist(s.s, &s.ccallable_list);
}

assert(object_worklist.len == 0);
Expand All @@ -3264,7 +3234,6 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
arraylist_free(&s.uniquing_objs);
arraylist_free(&s.fixup_types);
arraylist_free(&s.fixup_objs);
arraylist_free(&s.ccallable_list);
arraylist_free(&s.memowner_list);
arraylist_free(&s.memref_list);
arraylist_free(&s.relocs_list);
Expand Down Expand Up @@ -3475,7 +3444,7 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl
jl_array_t **extext_methods, jl_array_t **internal_methods,
jl_array_t **new_ext_cis, jl_array_t **method_roots_list,
jl_array_t **edges,
char **base, arraylist_t *ccallable_list, pkgcachesizes *cachesizes) JL_GC_DISABLED
pkgcachesizes *cachesizes) JL_GC_DISABLED
{
jl_task_t *ct = jl_current_task;
int en = jl_gc_enable(0);
Expand Down Expand Up @@ -3602,7 +3571,6 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl
ios_read(f, (char*)jl_array_data(s.link_ids_external_fnvars, uint32_t), nlinks_external_fnvars * sizeof(uint32_t));
}
uint32_t external_fns_begin = read_uint32(f);
jl_read_arraylist(s.s, ccallable_list ? ccallable_list : &s.ccallable_list);
if (s.incremental) {
assert(restored && init_order && extext_methods && internal_methods && new_ext_cis && method_roots_list && edges);
*restored = (jl_array_t*)jl_delayed_reloc(&s, offset_restored);
Expand All @@ -3622,8 +3590,6 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl

char *image_base = (char*)&sysimg.buf[0];
reloc_t *relocs_base = (reloc_t*)&relocs.buf[0];
if (base)
*base = image_base;

s.s = &sysimg;
jl_read_reloclist(&s, s.link_ids_gctags, GC_OLD | GC_IN_IMAGE); // gctags
Expand Down Expand Up @@ -3967,11 +3933,6 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl

s.s = &sysimg;
jl_update_all_fptrs(&s, image); // fptr relocs and registration
if (!ccallable_list) {
// TODO: jl_sysimg_handle or img_handle?
jl_reinit_ccallable(&s.ccallable_list, image_base, jl_sysimg_handle);
arraylist_free(&s.ccallable_list);
}
s.s = NULL;

ios_close(&fptr_record);
Expand Down Expand Up @@ -4049,8 +4010,6 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i

assert(datastartpos > 0 && datastartpos < dataendpos);
needs_permalloc = jl_options.permalloc_pkgimg || needs_permalloc;
char *base;
arraylist_t ccallable_list;

jl_value_t *restored = NULL;
jl_array_t *init_order = NULL, *extext_methods = NULL, *internal_methods = NULL, *new_ext_cis = NULL, *method_roots_list = NULL, *edges = NULL;
Expand Down Expand Up @@ -4080,7 +4039,7 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i
ios_static_buffer(f, sysimg, len);
pkgcachesizes cachesizes;
jl_restore_system_image_from_stream_(f, image, depmods, checksum, (jl_array_t**)&restored, &init_order, &extext_methods, &internal_methods, &new_ext_cis, &method_roots_list,
&edges, &base, &ccallable_list, &cachesizes);
&edges, &cachesizes);
JL_SIGATOMIC_END();

// No special processing of `new_ext_cis` is required because recaching handled it
Expand Down Expand Up @@ -4111,10 +4070,6 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i
// now permit more methods to be added again
JL_UNLOCK(&world_counter_lock);

// reinit ccallables
jl_reinit_ccallable(&ccallable_list, base, pkgimage_handle);
arraylist_free(&ccallable_list);

jl_value_t *ext_edges = new_ext_cis ? (jl_value_t*)new_ext_cis : jl_nothing;

if (completeinfo) {
Expand Down Expand Up @@ -4142,7 +4097,7 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i
static void jl_restore_system_image_from_stream(ios_t *f, jl_image_t *image, uint32_t checksum)
{
JL_TIMING(LOAD_IMAGE, LOAD_Sysimg);
jl_restore_system_image_from_stream_(f, image, NULL, checksum | ((uint64_t)0xfdfcfbfa << 32), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
jl_restore_system_image_from_stream_(f, image, NULL, checksum | ((uint64_t)0xfdfcfbfa << 32), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}

JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(void* pkgimage_handle, const char *buf, jl_image_t *image, size_t sz, jl_array_t *depmods, int completeinfo, const char *pkgname, int needs_permalloc)
Expand Down
Loading

0 comments on commit 9a5ac56

Please sign in to comment.