From cca51efe319a000d31baa08b440a23706889fa9f Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Wed, 26 Feb 2025 11:22:06 -0500 Subject: [PATCH 1/2] staticdata: Refactor sysimage loading Introduce `jl_image_buf_t` to represent the in-memory details of an unparsed system image and clean-up several global variables and split loading logic in staticdata.c so that we (almost) get everything we need from the sysimage handle at once. This allows sysimage loading to be separated into three phases: 1. Lookup the raw sysimage buffer as a `jl_image_buf_t` 2. For .so sysimages, parse the sysimage and initialize JIT targets, etc. 3. Finally load the sysimage into a `jl_image_t` Care was taken to preserve the existing behavior of calling `jl_set_sysimg_so` to configure the sysimage before initializing Julia, although this is likely to be next on the chopping block in a follow-up. --- src/init.c | 21 +++- src/jl_exported_funcs.inc | 3 +- src/julia.h | 26 ++++- src/processor.cpp | 22 +--- src/processor.h | 9 +- src/processor_arm.cpp | 8 +- src/processor_fallback.cpp | 8 +- src/processor_x86.cpp | 8 +- src/staticdata.c | 212 +++++++++++++++++++++---------------- test/cmdlineargs.jl | 2 +- 10 files changed, 182 insertions(+), 137 deletions(-) diff --git a/src/init.c b/src/init.c index 4703816b72793..ee57b807e24eb 100644 --- a/src/init.c +++ b/src/init.c @@ -868,21 +868,32 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ { JL_TIMING(JULIA_INIT, JULIA_INIT); jl_resolve_sysimg_location(rel); + // loads sysimg if available, and conditionally sets jl_options.cpu_target + jl_image_buf_t raw_image = { JL_IMAGE_KIND_NONE }; if (rel == JL_IMAGE_IN_MEMORY) { - jl_set_sysimg_so(jl_exe_handle); + raw_image = jl_set_sysimg_so(jl_exe_handle); jl_options.image_file = jl_options.julia_bin; } else if (jl_options.image_file) - jl_preload_sysimg_so(jl_options.image_file); + raw_image = jl_preload_sysimg(jl_options.image_file); + + jl_gc_notify_image_load(raw_image.data, raw_image.size); + if (jl_options.cpu_target == NULL) jl_options.cpu_target = "native"; - jl_init_codegen(); + // Parse image, perform relocations, and init JIT targets, etc. + jl_image_t image = jl_init_processor_sysimg(raw_image); + + jl_init_codegen(); jl_init_common_symbols(); - if (jl_options.image_file) { - jl_restore_system_image(jl_options.image_file); + + if (raw_image.kind != JL_IMAGE_KIND_NONE) { + // Load the .ji or .so sysimage + jl_restore_system_image(&image, raw_image); } else { + // No sysimage provided, init a minimal environment jl_init_types(); jl_global_roots_list = (jl_genericmemory_t*)jl_an_empty_memory_any; jl_global_roots_keyset = (jl_genericmemory_t*)jl_an_empty_memory_any; diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index bdf8cedd6b3f6..c80ebb5c92a8a 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -366,7 +366,7 @@ XX(jl_pointerset) \ XX(jl_pop_handler) \ XX(jl_pop_handler_noexcept) \ - XX(jl_preload_sysimg_so) \ + XX(jl_preload_sysimg) \ XX(jl_prepend_cwd) \ XX(jl_printf) \ XX(jl_print_backtrace) \ @@ -396,7 +396,6 @@ XX(jl_restore_incremental) \ XX(jl_restore_package_image_from_file) \ XX(jl_restore_system_image) \ - XX(jl_restore_system_image_data) \ XX(jl_rethrow) \ XX(jl_rethrow_other) \ XX(jl_running_on_valgrind) \ diff --git a/src/julia.h b/src/julia.h index 2341d3b655222..aa43b58aec141 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2159,6 +2159,25 @@ typedef enum { JL_IMAGE_IN_MEMORY = 2 } JL_IMAGE_SEARCH; +typedef enum { + JL_IMAGE_KIND_NONE = 0, + JL_IMAGE_KIND_JI, + JL_IMAGE_KIND_SO, +} jl_image_kind_t; + +// A loaded, but unparsed .ji or .so image file +typedef struct { + jl_image_kind_t kind; + void *handle; + const void *pointers; // jl_image_pointers_t * + const char *data; + size_t size; + uint64_t base; +} jl_image_buf_t; + +struct _jl_image_t; +typedef struct _jl_image_t jl_image_t; + JL_DLLIMPORT const char *jl_get_libdir(void); JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel); JL_DLLEXPORT void jl_init(void); @@ -2175,11 +2194,10 @@ JL_DLLEXPORT const char *jl_pathname_for_handle(void *handle); JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void); JL_DLLEXPORT int jl_deserialize_verify_header(ios_t *s); -JL_DLLEXPORT void jl_preload_sysimg_so(const char *fname); -JL_DLLEXPORT void jl_set_sysimg_so(void *handle); +JL_DLLEXPORT jl_image_buf_t jl_preload_sysimg(const char *fname); +JL_DLLEXPORT jl_image_buf_t jl_set_sysimg_so(void *handle); JL_DLLEXPORT void jl_create_system_image(void **, jl_array_t *worklist, bool_t emit_split, ios_t **s, ios_t **z, jl_array_t **udeps, int64_t *srctextpos); -JL_DLLEXPORT void jl_restore_system_image(const char *fname); -JL_DLLEXPORT void jl_restore_system_image_data(const char *buf, size_t len); +JL_DLLEXPORT void jl_restore_system_image(jl_image_t *image, jl_image_buf_t buf); JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname, jl_array_t *depmods, int complete, const char *pkgimage); JL_DLLEXPORT jl_value_t *jl_object_top_module(jl_value_t* v) JL_NOTSAFEPOINT; diff --git a/src/processor.cpp b/src/processor.cpp index 1fc005434a0cd..0288a76c55258 100644 --- a/src/processor.cpp +++ b/src/processor.cpp @@ -622,17 +622,15 @@ static inline llvm::SmallVector, 0> &get_cmdline_targets(F &&featu // Load sysimg, use the `callback` for dispatch and perform all relocations // for the selected target. template -static inline jl_image_t parse_sysimg(void *hdl, F &&callback) +static inline jl_image_t parse_sysimg(jl_image_buf_t image, F &&callback) { JL_TIMING(LOAD_IMAGE, LOAD_Processor); jl_image_t res{}; - const jl_image_pointers_t *pointers; - if (jl_system_image_size == 0) - jl_dlsym(hdl, "jl_image_pointers", (void**)&pointers, 1); - else - pointers = &jl_image_pointers; // libjulia-internal and sysimage statically linked + if (image.kind != JL_IMAGE_KIND_SO) + return res; + const jl_image_pointers_t *pointers = (const jl_image_pointers_t *)image.pointers; const void *ids = pointers->target_data; jl_value_t* rejection_reason = nullptr; JL_GC_PUSH1(&rejection_reason); @@ -794,17 +792,7 @@ static inline jl_image_t parse_sysimg(void *hdl, F &&callback) res.fptrs.nclones = clones.size(); } -#ifdef _OS_WINDOWS_ - res.base = (intptr_t)hdl; -#else - Dl_info dlinfo; - if (dladdr((void*)pointers, &dlinfo) != 0) { - res.base = (intptr_t)dlinfo.dli_fbase; - } - else { - res.base = 0; - } -#endif + res.base = image.base; { void *pgcstack_func_slot = pointers->ptls->pgcstack_func_slot; diff --git a/src/processor.h b/src/processor.h index 214f51845b12d..4fa596fe9cf2f 100644 --- a/src/processor.h +++ b/src/processor.h @@ -64,6 +64,7 @@ JL_DLLEXPORT int jl_test_cpu_feature(jl_cpu_feature_t feature); static const uint32_t jl_sysimg_tag_mask = 0x80000000u; static const uint32_t jl_sysimg_val_mask = ~((uint32_t)0x80000000u); +// A parsed image file typedef struct _jl_image_fptrs_t { // number of functions uint32_t nptrs; @@ -82,14 +83,14 @@ typedef struct _jl_image_fptrs_t { const uint32_t *clone_idxs; } jl_image_fptrs_t; -typedef struct { +struct _jl_image_t { uint64_t base; const char *gvars_base; const int32_t *gvars_offsets; uint32_t ngvars; jl_image_fptrs_t fptrs; void **jl_small_typeof; -} jl_image_t; +}; // The header for each image // Details important counts about the image @@ -206,8 +207,8 @@ typedef struct { * * Return the data about the function pointers selected. */ -jl_image_t jl_init_processor_sysimg(void *hdl); -jl_image_t jl_init_processor_pkgimg(void *hdl); +jl_image_t jl_init_processor_sysimg(jl_image_buf_t image); +jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image); // Return the name of the host CPU as a julia string. JL_DLLEXPORT jl_value_t *jl_get_cpu_name(void); diff --git a/src/processor_arm.cpp b/src/processor_arm.cpp index d28e527ed44e8..78312409c9442 100644 --- a/src/processor_arm.cpp +++ b/src/processor_arm.cpp @@ -1852,20 +1852,20 @@ JL_DLLEXPORT jl_value_t *jl_cpu_has_fma(int bits) #endif } -jl_image_t jl_init_processor_sysimg(void *hdl) +jl_image_t jl_init_processor_sysimg(jl_image_buf_t image) { if (!jit_targets.empty()) jl_error("JIT targets already initialized"); - return parse_sysimg(hdl, sysimg_init_cb); + return parse_sysimg(image, sysimg_init_cb); } -jl_image_t jl_init_processor_pkgimg(void *hdl) +jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image) { if (jit_targets.empty()) jl_error("JIT targets not initialized"); if (jit_targets.size() > 1) jl_error("Expected only one JIT target"); - return parse_sysimg(hdl, pkgimg_init_cb); + return parse_sysimg(image, pkgimg_init_cb); } JL_DLLEXPORT jl_value_t* jl_check_pkgimage_clones(char *data) diff --git a/src/processor_fallback.cpp b/src/processor_fallback.cpp index f8d9eb9fd9e73..036e37a2fd034 100644 --- a/src/processor_fallback.cpp +++ b/src/processor_fallback.cpp @@ -115,20 +115,20 @@ get_llvm_target_str(const TargetData<1> &data) using namespace Fallback; -jl_image_t jl_init_processor_sysimg(void *hdl) +jl_image_t jl_init_processor_sysimg(jl_image_buf_t image) { if (!jit_targets.empty()) jl_error("JIT targets already initialized"); - return parse_sysimg(hdl, sysimg_init_cb); + return parse_sysimg(image, sysimg_init_cb); } -jl_image_t jl_init_processor_pkgimg(void *hdl) +jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image) { if (jit_targets.empty()) jl_error("JIT targets not initialized"); if (jit_targets.size() > 1) jl_error("Expected only one JIT target"); - return parse_sysimg(hdl, pkgimg_init_cb); + return parse_sysimg(image, pkgimg_init_cb); } std::pair> jl_get_llvm_target(bool imaging, uint32_t &flags) diff --git a/src/processor_x86.cpp b/src/processor_x86.cpp index bf765be160ed2..9dd33caeefce1 100644 --- a/src/processor_x86.cpp +++ b/src/processor_x86.cpp @@ -1101,20 +1101,20 @@ JL_DLLEXPORT jl_value_t *jl_cpu_has_fma(int bits) return jl_false; } -jl_image_t jl_init_processor_sysimg(void *hdl) +jl_image_t jl_init_processor_sysimg(jl_image_buf_t image) { if (!jit_targets.empty()) jl_error("JIT targets already initialized"); - return parse_sysimg(hdl, sysimg_init_cb); + return parse_sysimg(image, sysimg_init_cb); } -jl_image_t jl_init_processor_pkgimg(void *hdl) +jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image) { if (jit_targets.empty()) jl_error("JIT targets not initialized"); if (jit_targets.size() > 1) jl_error("Expected only one JIT target"); - return parse_sysimg(hdl, pkgimg_init_cb); + return parse_sysimg(image, pkgimg_init_cb); } std::pair> jl_get_llvm_target(bool imaging, uint32_t &flags) diff --git a/src/staticdata.c b/src/staticdata.c index b09e89488b1d8..b43ed560d5b73 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -632,8 +632,7 @@ typedef struct { } pkgcachesizes; // --- Static Compile --- -static void *jl_sysimg_handle = NULL; -static jl_image_t sysimage; +static jl_image_buf_t jl_sysimage_buf = { JL_IMAGE_KIND_NONE }; static inline uintptr_t *sysimg_gvars(const char *base, const int32_t *offsets, size_t idx) { @@ -645,30 +644,6 @@ JL_DLLEXPORT int jl_running_on_valgrind(void) return RUNNING_ON_VALGRIND; } -static void jl_load_sysimg_so(void) -{ - assert(sysimage.fptrs.ptrs); // jl_init_processor_sysimg should already be run - - size_t *plen; - const char *sysimg_data; - - if (jl_system_image_size == 0) { - // in the usual case, the sysimage was not statically linked to libjulia-internal - // look up the external sysimage symbols via the dynamic linker - jl_dlsym(jl_sysimg_handle, "jl_system_image_size", (void **)&plen, 1); - jl_dlsym(jl_sysimg_handle, "jl_system_image_data", (void **)&sysimg_data, 1); - } else { - // the sysimage was statically linked directly against libjulia-internal - // use the internal symbols - plen = &jl_system_image_size; - sysimg_data = &jl_system_image_data; - } - - jl_gc_notify_image_load(sysimg_data, *plen); - jl_restore_system_image_data(sysimg_data, *plen); -} - - // --- serializer --- #define NBOX_C 1024 @@ -3501,33 +3476,111 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli JL_DLLEXPORT size_t ios_write_direct(ios_t *dest, ios_t *src); -// Takes in a path of the form "usr/lib/julia/sys.so" (jl_restore_system_image should be passed the same string) -JL_DLLEXPORT void jl_preload_sysimg_so(const char *fname) +// Takes in a path of the form "usr/lib/julia/sys.so" +JL_DLLEXPORT jl_image_buf_t jl_preload_sysimg(const char *fname) { - if (jl_sysimg_handle) - return; // embedded target already called jl_set_sysimg_so + if (jl_sysimage_buf.kind != JL_IMAGE_KIND_NONE) + return jl_sysimage_buf; char *dot = (char*) strrchr(fname, '.'); int is_ji = (dot && !strcmp(dot, ".ji")); - // Get handle to sys.so - if (!is_ji) // .ji extension => load .ji file only - jl_set_sysimg_so(jl_load_dynamic_library(fname, JL_RTLD_LOCAL | JL_RTLD_NOW, 1)); + if (is_ji) { + // .ji extension => load .ji file only + ios_t f; + + if (ios_file(&f, fname, 1, 0, 0, 0) == NULL) + jl_errorf("System image file \"%s\" not found.", fname); + ios_bufmode(&f, bm_none); + + JL_SIGATOMIC_BEGIN(); + + ios_seek_end(&f); + size_t len = ios_pos(&f); + char *sysimg = (char*)jl_gc_perm_alloc(len, 0, 64, 0); + ios_seek(&f, 0); + + if (ios_readall(&f, sysimg, len) != len) + jl_errorf("Error reading system image file."); + + ios_close(&f); + + JL_SIGATOMIC_END(); + + jl_sysimage_buf = (jl_image_buf_t) { + .kind = JL_IMAGE_KIND_JI, + .handle = NULL, + .pointers = NULL, + .data = sysimg, + .size = len, + .base = 0, + }; + return jl_sysimage_buf; + } else { + // Get handle to sys.so + return jl_set_sysimg_so(jl_load_dynamic_library(fname, JL_RTLD_LOCAL | JL_RTLD_NOW, 1)); + } } -// Allow passing in a module handle directly, rather than a path -JL_DLLEXPORT void jl_set_sysimg_so(void *handle) +// From a shared library handle, verify consistency and return a jl_image_buf_t +static jl_image_buf_t get_image_buf(void *handle, int is_pkgimage) { + size_t *plen; + const char *data; + const void *pointers; + uint64_t base; + + // verify that the linker resolved the symbols in this image against ourselves (libjulia-internal) void** (*get_jl_RTLD_DEFAULT_handle_addr)(void) = NULL; if (handle != jl_RTLD_DEFAULT_handle) { int symbol_found = jl_dlsym(handle, "get_jl_RTLD_DEFAULT_handle_addr", (void **)&get_jl_RTLD_DEFAULT_handle_addr, 0); if (!symbol_found || (void*)&jl_RTLD_DEFAULT_handle != (get_jl_RTLD_DEFAULT_handle_addr())) - jl_error("System image file failed consistency check: maybe opened the wrong version?"); + jl_error("Image file failed consistency check: maybe opened the wrong version?"); + } + + // verification passed, lookup the buffer pointers + if (jl_system_image_size == 0 || is_pkgimage) { + // in the usual case, the sysimage was not statically linked to libjulia-internal + // look up the external sysimage symbols via the dynamic linker + jl_dlsym(handle, "jl_system_image_size", (void **)&plen, 1); + jl_dlsym(handle, "jl_system_image_data", (void **)&data, 1); + jl_dlsym(handle, "jl_image_pointers", (void**)&pointers, 1); + } else { + // the sysimage was statically linked directly against libjulia-internal + // use the internal symbols + plen = &jl_system_image_size; + pointers = &jl_image_pointers; + data = &jl_system_image_data; } - if (jl_options.cpu_target == NULL) - jl_options.cpu_target = "native"; - jl_sysimg_handle = handle; - sysimage = jl_init_processor_sysimg(handle); + +#ifdef _OS_WINDOWS_ + base = (intptr_t)handle; +#else + Dl_info dlinfo; + if (dladdr((void*)pointers, &dlinfo) != 0) + base = (intptr_t)dlinfo.dli_fbase; + else + base = 0; +#endif + + return (jl_image_buf_t) { + .kind = JL_IMAGE_KIND_SO, + .handle = handle, + .pointers = pointers, + .data = data, + .size = *plen, + .base = base, + }; +} + +// Allow passing in a module handle directly, rather than a path +JL_DLLEXPORT jl_image_buf_t jl_set_sysimg_so(void *handle) +{ + if (jl_sysimage_buf.kind != JL_IMAGE_KIND_NONE) + return jl_sysimage_buf; + + jl_sysimage_buf = get_image_buf(handle, /* is_pkgimage */ 0); + return jl_sysimage_buf; } #ifndef JL_NDEBUG @@ -3630,7 +3683,8 @@ static int all_usings_unchanged_implicit(jl_module_t *mod) return unchanged_implicit; } -static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl_array_t *depmods, uint64_t checksum, +static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, void *image_handle, + jl_array_t *depmods, uint64_t checksum, /* outputs */ jl_array_t **restored, jl_array_t **init_order, jl_array_t **extext_methods, jl_array_t **internal_methods, jl_array_t **new_ext_cis, jl_array_t **method_roots_list, @@ -4142,8 +4196,7 @@ 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); + jl_reinit_ccallable(&s.ccallable_list, image_base, image_handle); arraylist_free(&s.ccallable_list); } s.s = NULL; @@ -4253,7 +4306,7 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i ios_close(f); 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, + jl_restore_system_image_from_stream_(f, image, pkgimage_handle, depmods, checksum, (jl_array_t**)&restored, &init_order, &extext_methods, &internal_methods, &new_ext_cis, &method_roots_list, &edges, &base, &ccallable_list, &cachesizes); JL_SIGATOMIC_END(); @@ -4312,16 +4365,16 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i return restored; } -static void jl_restore_system_image_from_stream(ios_t *f, jl_image_t *image, uint32_t checksum) +static void jl_restore_system_image_from_stream(ios_t *f, jl_image_t *image, void *image_handle, 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, image_handle, NULL, checksum | ((uint64_t)0xfdfcfbfa << 32), NULL, NULL, 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) +JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(void* pkgimage_handle, jl_image_buf_t buf, jl_image_t *image, jl_array_t *depmods, int completeinfo, const char *pkgname, int needs_permalloc) { ios_t f; - ios_static_buffer(&f, (char*)buf, sz); + ios_static_buffer(&f, (char*)buf.data, buf.size); jl_value_t *ret = jl_restore_package_image_from_stream(pkgimage_handle, &f, image, depmods, completeinfo, pkgname, needs_permalloc); ios_close(&f); return ret; @@ -4340,47 +4393,22 @@ JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname, jl_array_t *d return ret; } -// TODO: need to enforce that the alignment of the buffer is suitable for vectors -JL_DLLEXPORT void jl_restore_system_image(const char *fname) +JL_DLLEXPORT void jl_restore_system_image(jl_image_t *image, jl_image_buf_t buf) { -#ifndef JL_NDEBUG - char *dot = fname ? (char*)strrchr(fname, '.') : NULL; - int is_ji = (dot && !strcmp(dot, ".ji")); - assert((is_ji || jl_sysimg_handle) && "System image file not preloaded"); -#endif + ios_t f; - if (jl_sysimg_handle) { - // load the pre-compiled sysimage from jl_sysimg_handle - jl_load_sysimg_so(); - } - else { - ios_t f; - if (ios_file(&f, fname, 1, 0, 0, 0) == NULL) - jl_errorf("System image file \"%s\" not found.", fname); - ios_bufmode(&f, bm_none); - JL_SIGATOMIC_BEGIN(); - ios_seek_end(&f); - size_t len = ios_pos(&f); - char *sysimg = (char*)jl_gc_perm_alloc(len, 0, 64, 0); - ios_seek(&f, 0); - if (ios_readall(&f, sysimg, len) != len) - jl_errorf("Error reading system image file."); - ios_close(&f); - uint32_t checksum = jl_crc32c(0, sysimg, len); - ios_static_buffer(&f, sysimg, len); - jl_restore_system_image_from_stream(&f, &sysimage, checksum); - ios_close(&f); - JL_SIGATOMIC_END(); - } -} + if (buf.kind == JL_IMAGE_KIND_NONE) + return; + + if (buf.kind == JL_IMAGE_KIND_SO) + assert(image->fptrs.ptrs); // jl_init_processor_sysimg should already be run -JL_DLLEXPORT void jl_restore_system_image_data(const char *buf, size_t len) -{ - ios_t f; JL_SIGATOMIC_BEGIN(); - ios_static_buffer(&f, (char*)buf, len); - uint32_t checksum = jl_crc32c(0, buf, len); - jl_restore_system_image_from_stream(&f, &sysimage, checksum); + ios_static_buffer(&f, (char *)buf.data, buf.size); + + uint32_t checksum = jl_crc32c(0, buf.data, buf.size); + jl_restore_system_image_from_stream(&f, image, buf.handle, checksum); + ios_close(&f); JL_SIGATOMIC_END(); } @@ -4399,13 +4427,13 @@ JL_DLLEXPORT jl_value_t *jl_restore_package_image_from_file(const char *fname, j #endif jl_errorf("Error opening package file %s: %s\n", fname, reason); } - const char *pkgimg_data; - jl_dlsym(pkgimg_handle, "jl_system_image_data", (void **)&pkgimg_data, 1); - size_t *plen; - jl_dlsym(pkgimg_handle, "jl_system_image_size", (void **)&plen, 1); - jl_gc_notify_image_load(pkgimg_data, *plen); - jl_image_t pkgimage = jl_init_processor_pkgimg(pkgimg_handle); + jl_image_buf_t buf = get_image_buf(pkgimg_handle, /* is_pkgimage */ 1); + + jl_gc_notify_image_load(buf.data, buf.size); + + // Despite the name, this function actually parses the pkgimage + jl_image_t pkgimage = jl_init_processor_pkgimg(buf); if (ignore_native) { // Must disable using native code in possible downstream users of this code: @@ -4414,7 +4442,7 @@ JL_DLLEXPORT jl_value_t *jl_restore_package_image_from_file(const char *fname, j IMAGE_NATIVE_CODE_TAINTED = 1; } - jl_value_t* mod = jl_restore_incremental_from_buf(pkgimg_handle, pkgimg_data, &pkgimage, *plen, depmods, completeinfo, pkgname, 0); + jl_value_t* mod = jl_restore_incremental_from_buf(pkgimg_handle, buf, &pkgimage, depmods, completeinfo, pkgname, 0); return mod; } diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index fb44600886429..5d084e2040075 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -1046,7 +1046,7 @@ let exename = `$(Base.julia_cmd().exec[1]) -t 1` p = run(pipeline(`$exename --sysimage=$libjulia`, stderr=err), wait=false) close(err.in) let s = read(err, String) - @test s == "ERROR: System image file failed consistency check: maybe opened the wrong version?\n" + @test s == "ERROR: Image file failed consistency check: maybe opened the wrong version?\n" end @test errors_not_signals(p) @test p.exitcode == 1 From e0bde917f4cb6e324e3d8147e087000b03328e7a Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Thu, 27 Feb 2025 13:33:04 -0500 Subject: [PATCH 2/2] Pass around `jl_options.cpu_target` explicitly This (mostly) removes the only usage of `jl_options` internally in `processor_*.cpp` --- src/aotcompile.cpp | 2 +- src/init.c | 20 +++++++++++--------- src/jitlayers.cpp | 2 +- src/llvm-multiversioning.cpp | 2 +- src/processor.cpp | 13 +++++++------ src/processor.h | 6 +++--- src/processor_arm.cpp | 31 ++++++++++++++++--------------- src/processor_fallback.cpp | 31 ++++++++++++++++--------------- src/processor_x86.cpp | 32 +++++++++++++++++--------------- 9 files changed, 73 insertions(+), 66 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 84e5c096b86fb..9d6fee3c4d10b 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -2196,7 +2196,7 @@ void jl_dump_native_impl(void *native_code, builder.CreateRet(ConstantInt::get(T_int32, 1)); } if (imaging_mode) { - auto specs = jl_get_llvm_clone_targets(); + auto specs = jl_get_llvm_clone_targets(jl_options.cpu_target); const uint32_t base_flags = has_veccall ? JL_TARGET_VEC_CALL : 0; SmallVector data; auto push_i32 = [&] (uint32_t v) { diff --git a/src/init.c b/src/init.c index ee57b807e24eb..80f4b59acdc01 100644 --- a/src/init.c +++ b/src/init.c @@ -870,28 +870,29 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ jl_resolve_sysimg_location(rel); // loads sysimg if available, and conditionally sets jl_options.cpu_target - jl_image_buf_t raw_image = { JL_IMAGE_KIND_NONE }; + jl_image_buf_t sysimage = { JL_IMAGE_KIND_NONE }; if (rel == JL_IMAGE_IN_MEMORY) { - raw_image = jl_set_sysimg_so(jl_exe_handle); + sysimage = jl_set_sysimg_so(jl_exe_handle); jl_options.image_file = jl_options.julia_bin; } else if (jl_options.image_file) - raw_image = jl_preload_sysimg(jl_options.image_file); + sysimage = jl_preload_sysimg(jl_options.image_file); - jl_gc_notify_image_load(raw_image.data, raw_image.size); + if (sysimage.kind == JL_IMAGE_KIND_SO) + jl_gc_notify_image_load(sysimage.data, sysimage.size); if (jl_options.cpu_target == NULL) jl_options.cpu_target = "native"; // Parse image, perform relocations, and init JIT targets, etc. - jl_image_t image = jl_init_processor_sysimg(raw_image); + jl_image_t parsed_image = jl_init_processor_sysimg(sysimage, jl_options.cpu_target); jl_init_codegen(); jl_init_common_symbols(); - if (raw_image.kind != JL_IMAGE_KIND_NONE) { + if (sysimage.kind != JL_IMAGE_KIND_NONE) { // Load the .ji or .so sysimage - jl_restore_system_image(&image, raw_image); + jl_restore_system_image(&parsed_image, sysimage); } else { // No sysimage provided, init a minimal environment jl_init_types(); @@ -902,7 +903,7 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ jl_init_flisp(); jl_init_serializer(); - if (!jl_options.image_file) { + if (sysimage.kind == JL_IMAGE_KIND_NONE) { jl_top_module = jl_core_module; jl_init_intrinsic_functions(); jl_init_primitives(); @@ -930,7 +931,8 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ jl_gc_enable(1); - if (jl_options.image_file && (!jl_generating_output() || jl_options.incremental) && jl_module_init_order) { + if ((sysimage.kind != JL_IMAGE_KIND_NONE) && + (!jl_generating_output() || jl_options.incremental) && jl_module_init_order) { jl_array_t *init_order = jl_module_init_order; JL_GC_PUSH1(&init_order); jl_module_init_order = NULL; diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 59b3c75140f88..ed1c37931152d 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -1413,7 +1413,7 @@ namespace { #endif #endif uint32_t target_flags = 0; - auto target = jl_get_llvm_target(jl_generating_output(), target_flags); + auto target = jl_get_llvm_target(jl_options.cpu_target, jl_generating_output(), target_flags); auto &TheCPU = target.first; SmallVector targetFeatures(target.second.begin(), target.second.end()); std::string errorstr; diff --git a/src/llvm-multiversioning.cpp b/src/llvm-multiversioning.cpp index a76d076ebd6f3..02f77298513ee 100644 --- a/src/llvm-multiversioning.cpp +++ b/src/llvm-multiversioning.cpp @@ -216,7 +216,7 @@ static void annotate_module_clones(Module &M) { if (auto maybe_specs = get_target_specs(M)) { specs = std::move(*maybe_specs); } else { - auto full_specs = jl_get_llvm_clone_targets(); + auto full_specs = jl_get_llvm_clone_targets(jl_options.cpu_target); specs.reserve(full_specs.size()); for (auto &spec: full_specs) { specs.push_back(TargetSpec::fromSpec(spec)); diff --git a/src/processor.cpp b/src/processor.cpp index 0288a76c55258..6f95ee7f3790a 100644 --- a/src/processor.cpp +++ b/src/processor.cpp @@ -504,7 +504,8 @@ static inline llvm::SmallVector, 0> parse_cmdline(const char *option, F &&feature_cb) { if (!option) - option = "native"; + abort(); + llvm::SmallVector, 0> res; TargetData arg{}; auto reset_arg = [&] { @@ -612,17 +613,17 @@ parse_cmdline(const char *option, F &&feature_cb) // Cached version of command line parsing template -static inline llvm::SmallVector, 0> &get_cmdline_targets(F &&feature_cb) +static inline llvm::SmallVector, 0> &get_cmdline_targets(const char *cpu_target, F &&feature_cb) { static llvm::SmallVector, 0> targets = - parse_cmdline(jl_options.cpu_target, std::forward(feature_cb)); + parse_cmdline(cpu_target, std::forward(feature_cb)); return targets; } // Load sysimg, use the `callback` for dispatch and perform all relocations // for the selected target. template -static inline jl_image_t parse_sysimg(jl_image_buf_t image, F &&callback) +static inline jl_image_t parse_sysimg(jl_image_buf_t image, F &&callback, void *ctx) { JL_TIMING(LOAD_IMAGE, LOAD_Processor); jl_image_t res{}; @@ -634,7 +635,7 @@ static inline jl_image_t parse_sysimg(jl_image_buf_t image, F &&callback) const void *ids = pointers->target_data; jl_value_t* rejection_reason = nullptr; JL_GC_PUSH1(&rejection_reason); - uint32_t target_idx = callback(ids, &rejection_reason); + uint32_t target_idx = callback(ctx, ids, &rejection_reason); if (target_idx == UINT32_MAX) { jl_error(jl_string_ptr(rejection_reason)); } @@ -1012,7 +1013,7 @@ JL_DLLEXPORT jl_value_t *jl_get_cpu_features(void) } extern "C" JL_DLLEXPORT jl_value_t* jl_reflect_clone_targets() { - auto specs = jl_get_llvm_clone_targets(); + auto specs = jl_get_llvm_clone_targets(jl_options.cpu_target); const uint32_t base_flags = 0; llvm::SmallVector data; auto push_i32 = [&] (uint32_t v) { diff --git a/src/processor.h b/src/processor.h index 4fa596fe9cf2f..65b634fd0ba26 100644 --- a/src/processor.h +++ b/src/processor.h @@ -207,7 +207,7 @@ typedef struct { * * Return the data about the function pointers selected. */ -jl_image_t jl_init_processor_sysimg(jl_image_buf_t image); +jl_image_t jl_init_processor_sysimg(jl_image_buf_t image, const char *cpu_target); jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image); // Return the name of the host CPU as a julia string. @@ -252,7 +252,7 @@ extern JL_DLLEXPORT bool jl_processor_print_help; * If the detected/specified CPU name is not available on the LLVM version specified, * a fallback CPU name will be used. Unsupported features will be ignored. */ -extern "C" JL_DLLEXPORT std::pair> jl_get_llvm_target(bool imaging, uint32_t &flags) JL_NOTSAFEPOINT; +extern "C" JL_DLLEXPORT std::pair> jl_get_llvm_target(const char *cpu_target, bool imaging, uint32_t &flags) JL_NOTSAFEPOINT; /** * Returns the CPU name and feature string to be used by LLVM disassembler. @@ -276,7 +276,7 @@ struct jl_target_spec_t { /** * Return the list of targets to clone */ -extern "C" JL_DLLEXPORT llvm::SmallVector jl_get_llvm_clone_targets(void) JL_NOTSAFEPOINT; +extern "C" JL_DLLEXPORT llvm::SmallVector jl_get_llvm_clone_targets(const char *cpu_target) JL_NOTSAFEPOINT; // NOLINTEND(clang-diagnostic-return-type-c-linkage) struct FeatureName { const char *name; diff --git a/src/processor_arm.cpp b/src/processor_arm.cpp index 78312409c9442..66704a718a14d 100644 --- a/src/processor_arm.cpp +++ b/src/processor_arm.cpp @@ -1519,7 +1519,7 @@ static inline void disable_depends(FeatureList &features) ::disable_depends(features, Feature::deps, sizeof(Feature::deps) / sizeof(FeatureDep)); } -static const llvm::SmallVector, 0> &get_cmdline_targets(void) +static const llvm::SmallVector, 0> &get_cmdline_targets(const char *cpu_target) { auto feature_cb = [] (const char *str, size_t len, FeatureList &list) { #ifdef _CPU_AARCH64_ @@ -1536,7 +1536,7 @@ static const llvm::SmallVector, 0> &get_cmdline_targets(v set_bit(list, fbit, true); return true; }; - auto &targets = ::get_cmdline_targets(feature_cb); + auto &targets = ::get_cmdline_targets(cpu_target, feature_cb); for (auto &t: targets) { if (auto nname = normalize_cpu_name(t.name)) { t.name = nname; @@ -1599,10 +1599,11 @@ static int max_vector_size(const FeatureList &features) #endif } -static uint32_t sysimg_init_cb(const void *id, jl_value_t **rejection_reason) +static uint32_t sysimg_init_cb(void *ctx, const void *id, jl_value_t **rejection_reason) { // First see what target is requested for the JIT. - auto &cmdline = get_cmdline_targets(); + const char *cpu_target = (const char *)ctx; + auto &cmdline = get_cmdline_targets(cpu_target); TargetData target = arg_target_data(cmdline[0], true); // Then find the best match in the sysimg auto sysimg = deserialize_target_data((const uint8_t*)id); @@ -1626,7 +1627,7 @@ static uint32_t sysimg_init_cb(const void *id, jl_value_t **rejection_reason) return match.best_idx; } -static uint32_t pkgimg_init_cb(const void *id, jl_value_t **rejection_reason JL_REQUIRE_ROOTED_SLOT) +static uint32_t pkgimg_init_cb(void *ctx, const void *id, jl_value_t **rejection_reason JL_REQUIRE_ROOTED_SLOT) { TargetData target = jit_targets.front(); auto pkgimg = deserialize_target_data((const uint8_t*)id); @@ -1639,9 +1640,9 @@ static uint32_t pkgimg_init_cb(const void *id, jl_value_t **rejection_reason JL_ return match.best_idx; } -static void ensure_jit_target(bool imaging) +static void ensure_jit_target(const char *cpu_target, bool imaging) { - auto &cmdline = get_cmdline_targets(); + auto &cmdline = get_cmdline_targets(cpu_target); check_cmdline(cmdline, imaging); if (!jit_targets.empty()) return; @@ -1852,11 +1853,11 @@ JL_DLLEXPORT jl_value_t *jl_cpu_has_fma(int bits) #endif } -jl_image_t jl_init_processor_sysimg(jl_image_buf_t image) +jl_image_t jl_init_processor_sysimg(jl_image_buf_t image, const char *cpu_target) { if (!jit_targets.empty()) jl_error("JIT targets already initialized"); - return parse_sysimg(image, sysimg_init_cb); + return parse_sysimg(image, sysimg_init_cb, (void *)cpu_target); } jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image) @@ -1865,23 +1866,23 @@ jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image) jl_error("JIT targets not initialized"); if (jit_targets.size() > 1) jl_error("Expected only one JIT target"); - return parse_sysimg(image, pkgimg_init_cb); + return parse_sysimg(image, pkgimg_init_cb, NULL); } JL_DLLEXPORT jl_value_t* jl_check_pkgimage_clones(char *data) { jl_value_t *rejection_reason = NULL; JL_GC_PUSH1(&rejection_reason); - uint32_t match_idx = pkgimg_init_cb(data, &rejection_reason); + uint32_t match_idx = pkgimg_init_cb(NULL, data, &rejection_reason); JL_GC_POP(); if (match_idx == UINT32_MAX) return rejection_reason; return jl_nothing; } -std::pair> jl_get_llvm_target(bool imaging, uint32_t &flags) +std::pair> jl_get_llvm_target(const char *cpu_target, bool imaging, uint32_t &flags) { - ensure_jit_target(imaging); + ensure_jit_target(cpu_target, imaging); flags = jit_targets[0].en.flags; return get_llvm_target_vec(jit_targets[0]); } @@ -1900,10 +1901,10 @@ const std::pair &jl_get_llvm_disasm_target(void) } #ifndef __clang_gcanalyzer__ -llvm::SmallVector jl_get_llvm_clone_targets(void) +llvm::SmallVector jl_get_llvm_clone_targets(const char *cpu_target) { - auto &cmdline = get_cmdline_targets(); + auto &cmdline = get_cmdline_targets(cpu_target); check_cmdline(cmdline, true); llvm::SmallVector, 0> image_targets; for (auto &arg: cmdline) { diff --git a/src/processor_fallback.cpp b/src/processor_fallback.cpp index 036e37a2fd034..c8c8feb072345 100644 --- a/src/processor_fallback.cpp +++ b/src/processor_fallback.cpp @@ -13,12 +13,12 @@ static inline const std::string &host_cpu_name() return name; } -static const llvm::SmallVector, 0> &get_cmdline_targets(void) +static const llvm::SmallVector, 0> &get_cmdline_targets(const char *cpu_target) { auto feature_cb = [] (const char*, size_t, FeatureList<1>&) { return false; }; - return ::get_cmdline_targets<1>(feature_cb); + return ::get_cmdline_targets<1>(cpu_target, feature_cb); } static llvm::SmallVector, 0> jit_targets; @@ -36,10 +36,11 @@ static TargetData<1> arg_target_data(const TargetData<1> &arg, bool require_host return res; } -static uint32_t sysimg_init_cb(const void *id, jl_value_t **rejection_reason) +static uint32_t sysimg_init_cb(void *ctx, const void *id, jl_value_t **rejection_reason) { // First see what target is requested for the JIT. - auto &cmdline = get_cmdline_targets(); + const char *cpu_target = (const char *)ctx; + auto &cmdline = get_cmdline_targets(cpu_target); TargetData<1> target = arg_target_data(cmdline[0], true); // Find the last name match or use the default one. uint32_t best_idx = 0; @@ -54,7 +55,7 @@ static uint32_t sysimg_init_cb(const void *id, jl_value_t **rejection_reason) return best_idx; } -static uint32_t pkgimg_init_cb(const void *id, jl_value_t **rejection_reason) +static uint32_t pkgimg_init_cb(void *ctx, const void *id, jl_value_t **rejection_reason) { TargetData<1> target = jit_targets.front(); // Find the last name match or use the default one. @@ -70,9 +71,9 @@ static uint32_t pkgimg_init_cb(const void *id, jl_value_t **rejection_reason) return best_idx; } -static void ensure_jit_target(bool imaging) +static void ensure_jit_target(const char *cpu_target, bool imaging) { - auto &cmdline = get_cmdline_targets(); + auto &cmdline = get_cmdline_targets(cpu_target); check_cmdline(cmdline, imaging); if (!jit_targets.empty()) return; @@ -115,11 +116,11 @@ get_llvm_target_str(const TargetData<1> &data) using namespace Fallback; -jl_image_t jl_init_processor_sysimg(jl_image_buf_t image) +jl_image_t jl_init_processor_sysimg(jl_image_buf_t image, const char *cpu_target) { if (!jit_targets.empty()) jl_error("JIT targets already initialized"); - return parse_sysimg(image, sysimg_init_cb); + return parse_sysimg(image, sysimg_init_cb, (void *)cpu_target); } jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image) @@ -128,12 +129,12 @@ jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image) jl_error("JIT targets not initialized"); if (jit_targets.size() > 1) jl_error("Expected only one JIT target"); - return parse_sysimg(image, pkgimg_init_cb); + return parse_sysimg(image, pkgimg_init_cb, NULL); } -std::pair> jl_get_llvm_target(bool imaging, uint32_t &flags) +std::pair> jl_get_llvm_target(const char *cpu_target, bool imaging, uint32_t &flags) { - ensure_jit_target(imaging); + ensure_jit_target(cpu_target, imaging); flags = jit_targets[0].en.flags; return get_llvm_target_vec(jit_targets[0]); } @@ -145,10 +146,10 @@ const std::pair &jl_get_llvm_disasm_target(void) return res; } #ifndef __clang_gcanalyzer__ -llvm::SmallVector jl_get_llvm_clone_targets(void) +llvm::SmallVector jl_get_llvm_clone_targets(const char *cpu_target) { - auto &cmdline = get_cmdline_targets(); + auto &cmdline = get_cmdline_targets(cpu_target); check_cmdline(cmdline, true); llvm::SmallVector, 0> image_targets; for (auto &arg: cmdline) { @@ -192,7 +193,7 @@ JL_DLLEXPORT jl_value_t* jl_check_pkgimage_clones(char *data) { jl_value_t *rejection_reason = NULL; JL_GC_PUSH1(&rejection_reason); - uint32_t match_idx = pkgimg_init_cb(data, &rejection_reason); + uint32_t match_idx = pkgimg_init_cb(NULL, data, &rejection_reason); JL_GC_POP(); if (match_idx == UINT32_MAX) return rejection_reason; diff --git a/src/processor_x86.cpp b/src/processor_x86.cpp index 9dd33caeefce1..bd624943083ae 100644 --- a/src/processor_x86.cpp +++ b/src/processor_x86.cpp @@ -809,7 +809,7 @@ static inline void disable_depends(FeatureList &features) ::disable_depends(features, Feature::deps, sizeof(Feature::deps) / sizeof(FeatureDep)); } -static const llvm::SmallVector, 0> &get_cmdline_targets(void) +static const llvm::SmallVector, 0> &get_cmdline_targets(const char *cpu_target) { auto feature_cb = [] (const char *str, size_t len, FeatureList &list) { auto fbit = find_feature_bit(feature_names, nfeature_names, str, len); @@ -818,7 +818,7 @@ static const llvm::SmallVector, 0> &get_cmdline_targets(v set_bit(list, fbit, true); return true; }; - auto &targets = ::get_cmdline_targets(feature_cb); + auto &targets = ::get_cmdline_targets(cpu_target, feature_cb); for (auto &t: targets) { if (auto nname = normalize_cpu_name(t.name)) { t.name = nname; @@ -878,10 +878,11 @@ static int max_vector_size(const FeatureList &features) return 16; } -static uint32_t sysimg_init_cb(const void *id, jl_value_t** rejection_reason) +static uint32_t sysimg_init_cb(void *ctx, const void *id, jl_value_t** rejection_reason) { // First see what target is requested for the JIT. - auto &cmdline = get_cmdline_targets(); + const char *cpu_target = (const char *)ctx; + auto &cmdline = get_cmdline_targets(cpu_target); TargetData target = arg_target_data(cmdline[0], true); // Then find the best match in the sysimg auto sysimg = deserialize_target_data((const uint8_t*)id); @@ -924,7 +925,7 @@ static uint32_t sysimg_init_cb(const void *id, jl_value_t** rejection_reason) return match.best_idx; } -static uint32_t pkgimg_init_cb(const void *id, jl_value_t **rejection_reason) +static uint32_t pkgimg_init_cb(void *ctx, const void *id, jl_value_t **rejection_reason) { TargetData target = jit_targets.front(); auto pkgimg = deserialize_target_data((const uint8_t*)id); @@ -939,9 +940,9 @@ static uint32_t pkgimg_init_cb(const void *id, jl_value_t **rejection_reason) //This function serves as a fallback during bootstrapping, at that point we don't have a sysimage with native code // so we won't call sysimg_init_cb, else this function shouldn't do anything. -static void ensure_jit_target(bool imaging) +static void ensure_jit_target(const char *cpu_target, bool imaging) { - auto &cmdline = get_cmdline_targets(); + auto &cmdline = get_cmdline_targets(cpu_target); check_cmdline(cmdline, imaging); if (!jit_targets.empty()) return; @@ -1084,7 +1085,7 @@ JL_DLLEXPORT jl_value_t* jl_check_pkgimage_clones(char *data) { jl_value_t *rejection_reason = NULL; JL_GC_PUSH1(&rejection_reason); - uint32_t match_idx = pkgimg_init_cb(data, &rejection_reason); + uint32_t match_idx = pkgimg_init_cb(NULL, data, &rejection_reason); JL_GC_POP(); if (match_idx == UINT32_MAX) return rejection_reason; @@ -1101,11 +1102,11 @@ JL_DLLEXPORT jl_value_t *jl_cpu_has_fma(int bits) return jl_false; } -jl_image_t jl_init_processor_sysimg(jl_image_buf_t image) +jl_image_t jl_init_processor_sysimg(jl_image_buf_t image, const char *cpu_target) { if (!jit_targets.empty()) jl_error("JIT targets already initialized"); - return parse_sysimg(image, sysimg_init_cb); + return parse_sysimg(image, sysimg_init_cb, (void *)cpu_target); } jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image) @@ -1114,12 +1115,12 @@ jl_image_t jl_init_processor_pkgimg(jl_image_buf_t image) jl_error("JIT targets not initialized"); if (jit_targets.size() > 1) jl_error("Expected only one JIT target"); - return parse_sysimg(image, pkgimg_init_cb); + return parse_sysimg(image, pkgimg_init_cb, NULL); } -std::pair> jl_get_llvm_target(bool imaging, uint32_t &flags) +std::pair> jl_get_llvm_target(const char *cpu_target, bool imaging, uint32_t &flags) { - ensure_jit_target(imaging); + ensure_jit_target(cpu_target, imaging); flags = jit_targets[0].en.flags; return get_llvm_target_vec(jit_targets[0]); } @@ -1132,9 +1133,10 @@ const std::pair &jl_get_llvm_disasm_target(void) } //This function parses the -C command line to figure out which targets to multiversion to. #ifndef __clang_gcanalyzer__ -llvm::SmallVector jl_get_llvm_clone_targets(void) +llvm::SmallVector jl_get_llvm_clone_targets(const char *cpu_target) { - auto &cmdline = get_cmdline_targets(); + + auto &cmdline = get_cmdline_targets(cpu_target); check_cmdline(cmdline, true); llvm::SmallVector, 0> image_targets; for (auto &arg: cmdline) {