From 9a5ac56da59f90c9653247905cbe6918d7181c5a Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Wed, 8 Jan 2025 13:33:52 +0900 Subject: [PATCH] staticdata: remove `reinit_ccallable` 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. --- src/aotcompile.cpp | 2 +- src/codegen-stubs.c | 1 - src/gf.c | 38 +++++++++++ src/jitlayers.cpp | 134 -------------------------------------- src/jitlayers.h | 2 + src/jl_exported_funcs.inc | 2 - src/julia_internal.h | 1 - src/staticdata.c | 51 +-------------- test/llvmcall.jl | 54 --------------- test/precompile.jl | 33 ++++------ 10 files changed, 56 insertions(+), 262 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 0235758979cd1..d2842a1d701f8 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -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), ¶ms, 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 diff --git a/src/codegen-stubs.c b/src/codegen-stubs.c index 5e243ddda28c9..5fe5115a1912a 100644 --- a/src/codegen-stubs.c +++ b/src/codegen-stubs.c @@ -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 diff --git a/src/gf.c b/src/gf.c index ba28edfbeeff7..e7ed7793c9a08 100644 --- a/src/gf.c +++ b/src/gf.c @@ -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 diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 0acb7beaca9ab..eba619cd4cc80 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -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 ¶ms); - -// 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 = ¶ms; - } - 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) { diff --git a/src/jitlayers.h b/src/jitlayers.h index 7198c9b2f0210..85061e7a6d4d0 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -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 ¶ms); + jl_llvm_functions_t jl_emit_code( orc::ThreadSafeModule &M, jl_method_instance_t *mi, diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index cb48cf6f9962c..e2f915e3bf390 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -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) \ @@ -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) \ diff --git a/src/julia_internal.h b/src/julia_internal.h index a464025edf856..8bbadeda93f49 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -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 { diff --git a/src/staticdata.c b/src/staticdata.c index 7fad87652b26a..504aa1484e97e 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -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 @@ -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 @@ -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); @@ -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 @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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 @@ -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); @@ -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; @@ -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 @@ -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) { @@ -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) diff --git a/test/llvmcall.jl b/test/llvmcall.jl index ddf66ca680d45..9fd0505e24319 100644 --- a/test/llvmcall.jl +++ b/test/llvmcall.jl @@ -143,40 +143,6 @@ function call_jl_errno() end call_jl_errno() -module ObjLoadTest - using Base: llvmcall, @ccallable - using Test - didcall = false - """ jl_the_callback() - - Sets the global didcall when it did the call - """ - @ccallable Cvoid function jl_the_callback() - global didcall - didcall = true - nothing - end - @test_throws(ErrorException("@ccallable was already defined for this method name"), - @eval @ccallable String jl_the_callback(not_the_method::Int) = "other") - # Make sure everything up until here gets compiled - @test jl_the_callback() === nothing - @test jl_the_callback(1) == "other" - didcall = false - function do_the_call() - llvmcall( - ("""declare void @jl_the_callback() - define void @entry() #0 { - 0: - call void @jl_the_callback() - ret void - } - attributes #0 = { alwaysinline } - """, "entry"),Cvoid,Tuple{}) - end - do_the_call() - @test didcall -end - # Test for proper parenting local foo function foo() @@ -189,26 +155,6 @@ function foo() end code_llvm(devnull, foo, ()) -module CcallableRetTypeTest - using Base: llvmcall, @ccallable - using Test - @ccallable function jl_test_returns_float()::Float64 - return 42 - end - function do_the_call() - llvmcall( - ("""declare double @jl_test_returns_float() - define double @entry() #0 { - 0: - %1 = call double @jl_test_returns_float() - ret double %1 - } - attributes #0 = { alwaysinline } - """, "entry"),Float64,Tuple{}) - end - @test do_the_call() === 42.0 -end - # Issue #48093 - test that non-external globals are not deduplicated function kernel() Base.llvmcall((""" diff --git a/test/precompile.jl b/test/precompile.jl index 78a96250600a4..08c51a489d427 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -1,7 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -using Test, Distributed, Random, Logging -using REPL # doc lookup function +using Test, Distributed, Random, Logging, Libdl +using REPL # testing the doc lookup function should be outside of the scope of this file, but is currently tested here include("precompile_utils.jl") @@ -387,36 +387,27 @@ precompile_test_harness(false) do dir @test Base.object_build_id(Foo.a_vec_int) == Base.module_build_id(Foo) end - @eval begin function ccallable_test() - Base.llvmcall( - ("""declare i32 @f35014(i32) - define i32 @entry() { - 0: - %1 = call i32 @f35014(i32 3) - ret i32 %1 - }""", "entry" - ), Cint, Tuple{}) - end - @test ccallable_test() == 4 - end - cachedir = joinpath(dir, "compiled", "v$(VERSION.major).$(VERSION.minor)") cachedir2 = joinpath(dir2, "compiled", "v$(VERSION.major).$(VERSION.minor)") cachefile = joinpath(cachedir, "$Foo_module.ji") + @test isfile(cachefile) do_pkgimg = Base.JLOptions().use_pkgimages == 1 && Base.JLOptions().permalloc_pkgimg == 1 if do_pkgimg || Base.JLOptions().use_pkgimages == 0 if do_pkgimg - ocachefile = Base.ocachefile_from_cachefile(cachefile) + ocachefile = Base.ocachefile_from_cachefile(cachefile)::String + @test isfile(ocachefile) + let foo_ptr = Libdl.dlopen(ocachefile::String, RTLD_NOLOAD) + f35014_ptr = Libdl.dlsym(foo_ptr, :f35014) + @test ccall(f35014_ptr, Int32, (Int32,), 3) == 4 + end else ocachefile = nothing end # use _require_from_serialized to ensure that the test fails if # the module doesn't reload from the image: - @test_warn "@ccallable was already defined for this method name" begin - @test_logs (:warn, "Replacing module `$Foo_module`") begin - m = Base._require_from_serialized(Base.PkgId(Foo), cachefile, ocachefile, Foo_file) - @test isa(m, Module) - end + @test_logs (:warn, "Replacing module `$Foo_module`") begin + m = Base._require_from_serialized(Base.PkgId(Foo), cachefile, ocachefile, Foo_file) + @test isa(m, Module) end end