@@ -73,7 +73,8 @@ static bool runtime_sym_gvs(jl_codegen_params_t &emission_context, const char *f
7373static Value *runtime_sym_lookup (
7474 jl_codegen_params_t &emission_context,
7575 IRBuilder<> &irbuilder,
76- PointerType *funcptype, const char *f_lib,
76+ jl_codectx_t *ctx,
77+ PointerType *funcptype, const char *f_lib, jl_value_t *lib_expr,
7778 const char *f_name, Function *f,
7879 GlobalVariable *libptrgv,
7980 GlobalVariable *llvmgv, bool runtime_lib)
@@ -106,16 +107,25 @@ static Value *runtime_sym_lookup(
106107 assert (f->getParent () != NULL );
107108 f->getBasicBlockList ().push_back (dlsym_lookup);
108109 irbuilder.SetInsertPoint (dlsym_lookup);
109- Value *libname;
110- if (runtime_lib) {
111- libname = stringConstPtr (emission_context, irbuilder, f_lib);
110+ Value *llvmf;
111+ Value *nameval = stringConstPtr (emission_context, irbuilder, f_name);
112+ if (lib_expr) {
113+ jl_cgval_t libval = emit_expr (*ctx, lib_expr);
114+ llvmf = irbuilder.CreateCall (prepare_call_in (jl_builderModule (irbuilder), jllazydlsym_func),
115+ { boxed (*ctx, libval), nameval });
112116 }
113117 else {
114- // f_lib is actually one of the special sentinel values
115- libname = ConstantExpr::getIntToPtr (ConstantInt::get (T_size, (uintptr_t )f_lib), T_pint8);
118+ Value *libname;
119+ if (runtime_lib) {
120+ libname = stringConstPtr (emission_context, irbuilder, f_lib);
121+ }
122+ else {
123+ // f_lib is actually one of the special sentinel values
124+ libname = ConstantExpr::getIntToPtr (ConstantInt::get (T_size, (uintptr_t )f_lib), T_pint8);
125+ }
126+ llvmf = irbuilder.CreateCall (prepare_call_in (jl_builderModule (irbuilder), jldlsym_func),
127+ { libname, nameval, libptrgv });
116128 }
117- Value *llvmf = irbuilder.CreateCall (prepare_call_in (jl_builderModule (irbuilder), jldlsym_func),
118- { libname, stringConstPtr (emission_context, irbuilder, f_name), libptrgv });
119129 StoreInst *store = irbuilder.CreateAlignedStore (llvmf, llvmgv, sizeof (void *));
120130 store->setAtomic (AtomicOrdering::Release);
121131 irbuilder.CreateBr (ccall_bb);
@@ -130,15 +140,43 @@ static Value *runtime_sym_lookup(
130140
131141static Value *runtime_sym_lookup (
132142 jl_codectx_t &ctx,
133- PointerType *funcptype, const char *f_lib,
143+ PointerType *funcptype, const char *f_lib, jl_value_t *lib_expr,
144+ const char *f_name, Function *f,
145+ GlobalVariable *libptrgv,
146+ GlobalVariable *llvmgv, bool runtime_lib)
147+ {
148+ return runtime_sym_lookup (ctx.emission_context , ctx.builder , &ctx, funcptype, f_lib, lib_expr,
149+ f_name, f, libptrgv, llvmgv, runtime_lib);
150+ }
151+
152+ static Value *runtime_sym_lookup (
153+ jl_codectx_t &ctx,
154+ PointerType *funcptype, const char *f_lib, jl_value_t *lib_expr,
134155 const char *f_name, Function *f)
135156{
136157 GlobalVariable *libptrgv;
137158 GlobalVariable *llvmgv;
138- bool runtime_lib = runtime_sym_gvs (ctx.emission_context , f_lib, f_name, libptrgv, llvmgv);
139- libptrgv = prepare_global_in (jl_Module, libptrgv);
159+ bool runtime_lib;
160+ if (lib_expr) {
161+ // for computed library names, generate a global variable to cache the function
162+ // pointer just for this call site.
163+ runtime_lib = true ;
164+ libptrgv = NULL ;
165+ std::string gvname = " libname_" ;
166+ gvname += f_name;
167+ gvname += " _" ;
168+ gvname += std::to_string (globalUnique++);
169+ Module *M = ctx.emission_context .shared_module (jl_LLVMContext);
170+ llvmgv = new GlobalVariable (*M, T_pvoidfunc, false ,
171+ GlobalVariable::ExternalLinkage,
172+ Constant::getNullValue (T_pvoidfunc), gvname);
173+ }
174+ else {
175+ runtime_lib = runtime_sym_gvs (ctx.emission_context , f_lib, f_name, libptrgv, llvmgv);
176+ libptrgv = prepare_global_in (jl_Module, libptrgv);
177+ }
140178 llvmgv = prepare_global_in (jl_Module, llvmgv);
141- return runtime_sym_lookup (ctx. emission_context , ctx. builder , funcptype, f_lib, f_name, f, libptrgv, llvmgv, runtime_lib);
179+ return runtime_sym_lookup (ctx, funcptype, f_lib, lib_expr , f_name, f, libptrgv, llvmgv, runtime_lib);
142180}
143181
144182// Emit a "PLT" entry that will be lazily initialized
@@ -169,7 +207,7 @@ static GlobalVariable *emit_plt_thunk(
169207 fname);
170208 BasicBlock *b0 = BasicBlock::Create (jl_LLVMContext, " top" , plt);
171209 IRBuilder<> irbuilder (b0);
172- Value *ptr = runtime_sym_lookup (emission_context, irbuilder, funcptype, f_lib, f_name, plt, libptrgv,
210+ Value *ptr = runtime_sym_lookup (emission_context, irbuilder, NULL , funcptype, f_lib, NULL , f_name, plt, libptrgv,
173211 llvmgv, runtime_lib);
174212 StoreInst *store = irbuilder.CreateAlignedStore (irbuilder.CreateBitCast (ptr, T_pvoidfunc), got, sizeof (void *));
175213 store->setAtomic (AtomicOrdering::Release);
@@ -475,6 +513,7 @@ typedef struct {
475513 void (*fptr)(void ); // if the argument is a constant pointer
476514 const char *f_name; // if the symbol name is known
477515 const char *f_lib; // if a library name is specified
516+ jl_value_t *lib_expr; // expression to compute library path lazily
478517 jl_value_t *gcroot;
479518} native_sym_arg_t ;
480519
@@ -488,6 +527,24 @@ static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_va
488527
489528 jl_value_t *ptr = static_eval (ctx, arg, true );
490529 if (ptr == NULL ) {
530+ if (jl_is_expr (arg) && ((jl_expr_t *)arg)->head == call_sym && jl_expr_nargs (arg) == 3 &&
531+ jl_is_globalref (jl_exprarg (arg,0 )) && jl_globalref_mod (jl_exprarg (arg,0 )) == jl_core_module &&
532+ jl_globalref_name (jl_exprarg (arg,0 )) == jl_symbol (" tuple" )) {
533+ // attempt to interpret a non-constant 2-tuple expression as (func_name, lib_name()), where
534+ // `lib_name()` will be executed when first used.
535+ jl_value_t *name_val = static_eval (ctx, jl_exprarg (arg,1 ));
536+ if (name_val && jl_is_symbol (name_val)) {
537+ f_name = jl_symbol_name ((jl_sym_t *)name_val);
538+ out.lib_expr = jl_exprarg (arg, 2 );
539+ return ;
540+ }
541+ else if (name_val && jl_is_string (name_val)) {
542+ f_name = jl_string_data (name_val);
543+ out.gcroot = name_val;
544+ out.lib_expr = jl_exprarg (arg, 2 );
545+ return ;
546+ }
547+ }
491548 jl_cgval_t arg1 = emit_expr (ctx, arg);
492549 jl_value_t *ptr_ty = arg1.typ ;
493550 if (!jl_is_cpointer_type (ptr_ty)) {
@@ -586,8 +643,11 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg
586643 jl_printf (JL_STDERR," WARNING: literal address used in cglobal for %s; code cannot be statically compiled\n " , sym.f_name );
587644 }
588645 else {
589- if (imaging_mode) {
590- res = runtime_sym_lookup (ctx, cast<PointerType>(T_pint8), sym.f_lib , sym.f_name , ctx.f );
646+ if (sym.lib_expr ) {
647+ res = runtime_sym_lookup (ctx, cast<PointerType>(T_pint8), NULL , sym.lib_expr , sym.f_name , ctx.f );
648+ }
649+ else if (imaging_mode) {
650+ res = runtime_sym_lookup (ctx, cast<PointerType>(T_pint8), sym.f_lib , NULL , sym.f_name , ctx.f );
591651 res = ctx.builder .CreatePtrToInt (res, lrt);
592652 }
593653 else {
@@ -597,7 +657,7 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg
597657 if (!libsym || !jl_dlsym (libsym, sym.f_name , &symaddr, 0 )) {
598658 // Error mode, either the library or the symbol couldn't be find during compiletime.
599659 // Fallback to a runtime symbol lookup.
600- res = runtime_sym_lookup (ctx, cast<PointerType>(T_pint8), sym.f_lib , sym.f_name , ctx.f );
660+ res = runtime_sym_lookup (ctx, cast<PointerType>(T_pint8), sym.f_lib , NULL , sym.f_name , ctx.f );
601661 res = ctx.builder .CreatePtrToInt (res, lrt);
602662 } else {
603663 // since we aren't saving this code, there's no sense in
@@ -1716,11 +1776,14 @@ jl_cgval_t function_sig_t::emit_a_ccall(
17161776 else {
17171777 assert (symarg.f_name != NULL );
17181778 PointerType *funcptype = PointerType::get (functype, 0 );
1719- if (imaging_mode) {
1779+ if (symarg.lib_expr ) {
1780+ llvmf = runtime_sym_lookup (ctx, funcptype, NULL , symarg.lib_expr , symarg.f_name , ctx.f );
1781+ }
1782+ else if (imaging_mode) {
17201783 // vararg requires musttail,
17211784 // but musttail is incompatible with noreturn.
17221785 if (functype->isVarArg ())
1723- llvmf = runtime_sym_lookup (ctx, funcptype, symarg.f_lib , symarg.f_name , ctx.f );
1786+ llvmf = runtime_sym_lookup (ctx, funcptype, symarg.f_lib , NULL , symarg.f_name , ctx.f );
17241787 else
17251788 llvmf = emit_plt (ctx, functype, attributes, cc, symarg.f_lib , symarg.f_name );
17261789 }
@@ -1730,7 +1793,7 @@ jl_cgval_t function_sig_t::emit_a_ccall(
17301793 if (!libsym || !jl_dlsym (libsym, symarg.f_name , &symaddr, 0 )) {
17311794 // either the library or the symbol could not be found, place a runtime
17321795 // lookup here instead.
1733- llvmf = runtime_sym_lookup (ctx, funcptype, symarg.f_lib , symarg.f_name , ctx.f );
1796+ llvmf = runtime_sym_lookup (ctx, funcptype, symarg.f_lib , NULL , symarg.f_name , ctx.f );
17341797 } else {
17351798 // since we aren't saving this code, there's no sense in
17361799 // putting anything complicated here: just JIT the function address
0 commit comments