@@ -1542,7 +1542,7 @@ class jl_codectx_t {
15421542 jl_codegen_params_t &emission_context;
15431543 llvm::MapVector<jl_code_instance_t *, jl_codegen_call_target_t > call_targets;
15441544 std::map<void *, GlobalVariable*> &global_targets;
1545- std::map<std::tuple<jl_code_instance_t *, bool >, Function *> &external_calls;
1545+ std::map<std::tuple<jl_code_instance_t *, bool >, GlobalVariable *> &external_calls;
15461546 Function *f = NULL ;
15471547 // local var info. globals are not in here.
15481548 std::vector<jl_varinfo_t > slots;
@@ -1704,7 +1704,7 @@ static Value *get_current_task(jl_codectx_t &ctx);
17041704static Value *get_current_ptls (jl_codectx_t &ctx);
17051705static Value *get_last_age_field (jl_codectx_t &ctx);
17061706static void CreateTrap (IRBuilder<> &irbuilder, bool create_new_block = true );
1707- static CallInst *emit_jlcall (jl_codectx_t &ctx, Function * theFptr, Value *theF,
1707+ static CallInst *emit_jlcall (jl_codectx_t &ctx, FunctionCallee theFptr, Value *theF,
17081708 const jl_cgval_t *args, size_t nargs, JuliaFunction *trampoline);
17091709static CallInst *emit_jlcall (jl_codectx_t &ctx, JuliaFunction *theFptr, Value *theF,
17101710 const jl_cgval_t *args, size_t nargs, JuliaFunction *trampoline);
@@ -4039,14 +4039,14 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
40394039}
40404040
40414041// Returns ctx.types().T_prjlvalue
4042- static CallInst *emit_jlcall (jl_codectx_t &ctx, Function * theFptr, Value *theF,
4042+ static CallInst *emit_jlcall (jl_codectx_t &ctx, FunctionCallee theFptr, Value *theF,
40434043 const jl_cgval_t *argv, size_t nargs, JuliaFunction *trampoline)
40444044{
40454045 ++EmittedJLCalls;
40464046 Function *TheTrampoline = prepare_call (trampoline);
40474047 // emit arguments
40484048 SmallVector<Value*, 4 > theArgs;
4049- theArgs.push_back (theFptr);
4049+ theArgs.push_back (theFptr. getCallee () );
40504050 if (theF)
40514051 theArgs.push_back (theF);
40524052 for (size_t i = 0 ; i < nargs; i++) {
@@ -4067,7 +4067,7 @@ static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction *theFptr, Value *t
40674067}
40684068
40694069
4070- static jl_cgval_t emit_call_specfun_other (jl_codectx_t &ctx, jl_method_instance_t *mi, jl_value_t *jlretty, StringRef specFunctionObject,
4070+ static jl_cgval_t emit_call_specfun_other (jl_codectx_t &ctx, jl_method_instance_t *mi, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal,
40714071 const jl_cgval_t *argv, size_t nargs, jl_returninfo_t ::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty)
40724072{
40734073 ++EmittedSpecfunCalls;
@@ -4143,7 +4143,22 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_
41434143 idx++;
41444144 }
41454145 assert (idx == nfargs);
4146- CallInst *call = ctx.builder .CreateCall (returninfo.decl , ArrayRef<Value*>(&argvals[0 ], nfargs));
4146+ Value *callee = returninfo.decl ;
4147+ if (fromexternal) {
4148+ std::string namep (" p" );
4149+ namep += returninfo.decl ->getName ();
4150+ GlobalVariable *GV = cast_or_null<GlobalVariable>(jl_Module->getNamedValue (namep));
4151+ if (GV == nullptr ) {
4152+ GV = new GlobalVariable (*jl_Module, callee->getType (), false ,
4153+ GlobalVariable::ExternalLinkage,
4154+ Constant::getNullValue (callee->getType ()),
4155+ namep);
4156+ ctx.external_calls [std::make_tuple (fromexternal, true )] = GV;
4157+ }
4158+ jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA (ctx, ctx.tbaa ().tbaa_const );
4159+ callee = ai.decorateInst (ctx.builder .CreateAlignedLoad (callee->getType (), GV, Align (sizeof (void *))));
4160+ }
4161+ CallInst *call = ctx.builder .CreateCall (cft, callee, ArrayRef<Value*>(&argvals[0 ], nfargs));
41474162 call->setAttributes (returninfo.decl ->getAttributes ());
41484163
41494164 jl_cgval_t retval;
@@ -4182,13 +4197,30 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_
41824197 return update_julia_type (ctx, retval, inferred_retty);
41834198}
41844199
4185- static jl_cgval_t emit_call_specfun_boxed (jl_codectx_t &ctx, jl_value_t *jlretty, StringRef specFunctionObject,
4200+ static jl_cgval_t emit_call_specfun_boxed (jl_codectx_t &ctx, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal,
41864201 const jl_cgval_t *argv, size_t nargs, jl_value_t *inferred_retty)
41874202{
4188- auto theFptr = cast<Function>(
4189- jl_Module->getOrInsertFunction (specFunctionObject, ctx.types ().T_jlfunc ).getCallee ());
4190- addRetAttr (theFptr, Attribute::NonNull);
4191- Value *ret = emit_jlcall (ctx, theFptr, nullptr , argv, nargs, julia_call);
4203+ Value *theFptr;
4204+ if (fromexternal) {
4205+ std::string namep (" p" );
4206+ namep += specFunctionObject;
4207+ GlobalVariable *GV = cast_or_null<GlobalVariable>(jl_Module->getNamedValue (namep));
4208+ Type *pfunc = ctx.types ().T_jlfunc ->getPointerTo ();
4209+ if (GV == nullptr ) {
4210+ GV = new GlobalVariable (*jl_Module, pfunc, false ,
4211+ GlobalVariable::ExternalLinkage,
4212+ Constant::getNullValue (pfunc),
4213+ namep);
4214+ ctx.external_calls [std::make_tuple (fromexternal, false )] = GV;
4215+ }
4216+ jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA (ctx, ctx.tbaa ().tbaa_const );
4217+ theFptr = ai.decorateInst (ctx.builder .CreateAlignedLoad (pfunc, GV, Align (sizeof (void *))));
4218+ }
4219+ else {
4220+ theFptr = jl_Module->getOrInsertFunction (specFunctionObject, ctx.types ().T_jlfunc ).getCallee ();
4221+ addRetAttr (cast<Function>(theFptr), Attribute::NonNull);
4222+ }
4223+ Value *ret = emit_jlcall (ctx, FunctionCallee (ctx.types ().T_jlfunc , theFptr), nullptr , argv, nargs, julia_call);
41924224 return update_julia_type (ctx, mark_julia_type (ctx, ret, true , jlretty), inferred_retty);
41934225}
41944226
@@ -4223,12 +4255,12 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, const
42234255 FunctionType *ft = ctx.f ->getFunctionType ();
42244256 StringRef protoname = ctx.f ->getName ();
42254257 if (ft == ctx.types ().T_jlfunc ) {
4226- result = emit_call_specfun_boxed (ctx, ctx.rettype , protoname, argv, nargs, rt);
4258+ result = emit_call_specfun_boxed (ctx, ctx.rettype , protoname, nullptr , argv, nargs, rt);
42274259 handled = true ;
42284260 }
42294261 else if (ft != ctx.types ().T_jlfuncparams ) {
42304262 unsigned return_roots = 0 ;
4231- result = emit_call_specfun_other (ctx, mi, ctx.rettype , protoname, argv, nargs, &cc, &return_roots, rt);
4263+ result = emit_call_specfun_other (ctx, mi, ctx.rettype , protoname, nullptr , argv, nargs, &cc, &return_roots, rt);
42324264 handled = true ;
42334265 }
42344266 }
@@ -4248,16 +4280,17 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, const
42484280 std::string name;
42494281 StringRef protoname;
42504282 bool need_to_emit = true ;
4251- bool cache_valid = ctx.use_cache ;
4283+ bool cache_valid = ctx.use_cache || ctx. external_linkage ;
42524284 bool external = false ;
4253- if (ctx. external_linkage ) {
4254- if ( 0 && jl_object_in_image (( jl_value_t *)codeinst)) {
4255- // Target is present in another pkgimage
4256- cache_valid = true ;
4257- external = true ;
4258- }
4285+
4286+ // Check if we already queued this up
4287+ auto it = ctx. call_targets . find (codeinst);
4288+ if (need_to_emit && it != ctx. call_targets . end ()) {
4289+ protoname = std::get< 2 >(it-> second )-> getName () ;
4290+ need_to_emit = cache_valid = false ;
42594291 }
42604292
4293+ // Check if it is already compiled (either JIT or externally)
42614294 if (cache_valid) {
42624295 // optimization: emit the correct name immediately, if we know it
42634296 // TODO: use `emitted` map here too to try to consolidate names?
@@ -4270,32 +4303,30 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, const
42704303 invoke = jl_atomic_load_relaxed (&codeinst->invoke );
42714304 if (specsig ? jl_atomic_load_relaxed (&codeinst->specsigflags ) & 0b1 : invoke == jl_fptr_args_addr) {
42724305 protoname = jl_ExecutionEngine->getFunctionAtAddress ((uintptr_t )fptr, codeinst);
4273- need_to_emit = false ;
4306+ if (ctx.external_linkage ) {
4307+ // TODO: Add !specsig support to aotcompile.cpp
4308+ // Check that the codeinst is containing native code
4309+ if (specsig && jl_atomic_load_relaxed (&codeinst->specsigflags ) & 0b100 ) {
4310+ external = true ;
4311+ need_to_emit = false ;
4312+ }
4313+ }
4314+ else { // ctx.use_cache
4315+ need_to_emit = false ;
4316+ }
42744317 }
42754318 }
42764319 }
4277- auto it = ctx.call_targets .find (codeinst);
4278- if (need_to_emit && it != ctx.call_targets .end ()) {
4279- protoname = std::get<2 >(it->second )->getName ();
4280- need_to_emit = false ;
4281- }
42824320 if (need_to_emit) {
42834321 raw_string_ostream (name) << (specsig ? " j_" : " j1_" ) << name_from_method_instance (mi) << " _" << jl_atomic_fetch_add (&globalUniqueGeneratedNames, 1 );
42844322 protoname = StringRef (name);
42854323 }
42864324 jl_returninfo_t ::CallingConv cc = jl_returninfo_t ::CallingConv::Boxed;
42874325 unsigned return_roots = 0 ;
42884326 if (specsig)
4289- result = emit_call_specfun_other (ctx, mi, codeinst->rettype , protoname, argv, nargs, &cc, &return_roots, rt);
4327+ result = emit_call_specfun_other (ctx, mi, codeinst->rettype , protoname, external ? codeinst : nullptr , argv, nargs, &cc, &return_roots, rt);
42904328 else
4291- result = emit_call_specfun_boxed (ctx, codeinst->rettype , protoname, argv, nargs, rt);
4292- if (external) {
4293- assert (!need_to_emit);
4294- auto calledF = jl_Module->getFunction (protoname);
4295- assert (calledF);
4296- // TODO: Check if already present?
4297- ctx.external_calls [std::make_tuple (codeinst, specsig)] = calledF;
4298- }
4329+ result = emit_call_specfun_boxed (ctx, codeinst->rettype , protoname, external ? codeinst : nullptr , argv, nargs, rt);
42994330 handled = true ;
43004331 if (need_to_emit) {
43014332 Function *trampoline_decl = cast<Function>(jl_Module->getNamedValue (protoname));
@@ -5617,14 +5648,7 @@ static Function *emit_tojlinvoke(jl_code_instance_t *codeinst, Module *M, jl_cod
56175648 Function *theFunc;
56185649 Value *theFarg;
56195650 auto invoke = jl_atomic_load_relaxed (&codeinst->invoke );
5620-
56215651 bool cache_valid = params.cache ;
5622- if (params.external_linkage ) {
5623- if (0 && jl_object_in_image ((jl_value_t *)codeinst)) {
5624- // Target is present in another pkgimage
5625- cache_valid = true ;
5626- }
5627- }
56285652
56295653 if (cache_valid && invoke != NULL ) {
56305654 StringRef theFptrName = jl_ExecutionEngine->getFunctionAtAddress ((uintptr_t )invoke, codeinst);
@@ -8537,9 +8561,6 @@ void jl_compile_workqueue(
85378561 bool preal_specsig = false ;
85388562 auto invoke = jl_atomic_load_acquire (&codeinst->invoke );
85398563 bool cache_valid = params.cache ;
8540- if (params.external_linkage ) {
8541- cache_valid = 0 && jl_object_in_image ((jl_value_t *)codeinst);
8542- }
85438564 // WARNING: isspecsig is protected by the codegen-lock. If that lock is removed, then the isspecsig load needs to be properly atomically sequenced with this.
85448565 if (cache_valid && invoke != NULL ) {
85458566 auto fptr = jl_atomic_load_relaxed (&codeinst->specptr .fptr );
0 commit comments