@@ -473,14 +473,15 @@ jl_emit_codeinsts_to_jit_impl(jl_code_instance_t **codeinsts, jl_code_info_t **s
473473 JL_TIMING (CODEINST_COMPILE , CODEINST_COMPILE );
474474
475475 // Partition the batch by effective optimization level and emit each group as
476- // its own LLVM module.
476+ // its own LLVM module, then add them together so the batch stays atomic .
477477 std::map<int , SmallVector<int , 0 >> groups;
478478 for (int i = 0 ; i < len; ++i) {
479479 if (jl_atomic_load_relaxed (&codeinsts[i]->invoke ))
480480 continue ; // already compiled
481481 groups[jl_codeinst_optlevel (codeinsts[i])].push_back (i);
482482 }
483483
484+ SmallVector<jl_emitted_output_t > outputs;
484485 for (auto &group : groups) {
485486 SmallVector<int , 0 > &idxs = group.second ;
486487 const char *name = name_from_method_instance (jl_get_ci_mi (codeinsts[idxs.back ()]));
@@ -532,10 +533,12 @@ jl_emit_codeinsts_to_jit_impl(jl_code_instance_t **codeinsts, jl_code_info_t **s
532533 emit_llvmcall_modules (out);
533534
534535 auto &ES = jl_ExecutionEngine->getExecutionSession ();
535- jl_emitted_output_t emitted =
536- out.finish (std::move (ctx), std::move (mod), *ES .getSymbolStringPool ());
537- jl_ExecutionEngine->addOutput (std::move (emitted));
536+ outputs.push_back (
537+ out.finish (std::move (ctx), std::move (mod), *ES .getSymbolStringPool ()));
538538 }
539+
540+ if (!outputs.empty ())
541+ jl_ExecutionEngine->addOutputs (outputs);
539542}
540543
541544extern " C" JL_DLLEXPORT_CODEGEN
@@ -1975,17 +1978,27 @@ static void timing_print_module_names(jl_timing_block_t *block,
19751978#endif
19761979
19771980void JuliaOJIT::addOutput (jl_emitted_output_t O)
1981+ {
1982+ addOutputs (MutableArrayRef<jl_emitted_output_t >(&O, 1 ));
1983+ }
1984+
1985+ void JuliaOJIT::addOutputs (MutableArrayRef<jl_emitted_output_t > Os)
19781986{
19791987 JL_TIMING (LLVM_JIT , JIT_Total);
1980- ++ModulesAdded;
1981- #ifdef ENABLE_TIMINGS
1982- timing_print_module_names (JL_TIMING_DEFAULT_BLOCK , *O.module );
1983- #endif
1988+ // Register and define every module before releasing the lock, so the whole
1989+ // batch becomes visible at once and cross-module references between
1990+ // co-emitted CodeInstances never fall back to a tojlinvoke trampoline.
19841991 std::unique_lock Lock{LinkerMutex};
1985- auto MU = std::make_unique<JLMaterializationUnit>(
1986- JLMaterializationUnit::Create (*this , ObjectLayer, std::move (O)));
19871992 ExitOnError check{" Failed to add objectfile to JIT!" };
1988- check (JD .define (MU , JD .getDefaultResourceTracker ()));
1993+ for (auto &O : Os) {
1994+ ++ModulesAdded;
1995+ #ifdef ENABLE_TIMINGS
1996+ timing_print_module_names (JL_TIMING_DEFAULT_BLOCK , *O.module );
1997+ #endif
1998+ auto MU = std::make_unique<JLMaterializationUnit>(
1999+ JLMaterializationUnit::Create (*this , ObjectLayer, std::move (O)));
2000+ check (JD .define (MU , JD .getDefaultResourceTracker ()));
2001+ }
19892002}
19902003
19912004orc::JITDylib& JuliaOJIT::createJITDylib (StringRef NamePrefix)
0 commit comments