@@ -73,7 +73,8 @@ static bool runtime_sym_gvs(jl_codegen_params_t &emission_context, const char *f
73
73
static Value *runtime_sym_lookup (
74
74
jl_codegen_params_t &emission_context,
75
75
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,
77
78
const char *f_name, Function *f,
78
79
GlobalVariable *libptrgv,
79
80
GlobalVariable *llvmgv, bool runtime_lib)
@@ -106,16 +107,25 @@ static Value *runtime_sym_lookup(
106
107
assert (f->getParent () != NULL );
107
108
f->getBasicBlockList ().push_back (dlsym_lookup);
108
109
irbuilder.SetInsertPoint (dlsym_lookup);
109
- Value *libname;
110
- if (runtime_lib) {
111
- libname = stringConstPtr (emission_context, irbuilder, f_lib);
110
+ Instruction *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 });
112
116
}
113
117
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 });
116
128
}
117
- Value *llvmf = irbuilder.CreateCall (prepare_call_in (jl_builderModule (irbuilder), jldlsym_func),
118
- { libname, stringConstPtr (emission_context, irbuilder, f_name), libptrgv });
119
129
StoreInst *store = irbuilder.CreateAlignedStore (llvmf, llvmgv, Align (sizeof (void *)));
120
130
store->setAtomic (AtomicOrdering::Release);
121
131
irbuilder.CreateBr (ccall_bb);
@@ -124,21 +134,49 @@ static Value *runtime_sym_lookup(
124
134
irbuilder.SetInsertPoint (ccall_bb);
125
135
PHINode *p = irbuilder.CreatePHI (T_pvoidfunc, 2 );
126
136
p->addIncoming (llvmf_orig, enter_bb);
127
- p->addIncoming (llvmf, dlsym_lookup );
137
+ p->addIncoming (llvmf, llvmf-> getParent () );
128
138
return irbuilder.CreateBitCast (p, funcptype);
129
139
}
130
140
131
141
static Value *runtime_sym_lookup (
132
142
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,
134
155
const char *f_name, Function *f)
135
156
{
136
157
GlobalVariable *libptrgv;
137
158
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
+ }
140
178
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);
142
180
}
143
181
144
182
// Emit a "PLT" entry that will be lazily initialized
@@ -169,7 +207,7 @@ static GlobalVariable *emit_plt_thunk(
169
207
fname);
170
208
BasicBlock *b0 = BasicBlock::Create (jl_LLVMContext, " top" , plt);
171
209
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,
173
211
llvmgv, runtime_lib);
174
212
StoreInst *store = irbuilder.CreateAlignedStore (irbuilder.CreateBitCast (ptr, T_pvoidfunc), got, Align (sizeof (void *)));
175
213
store->setAtomic (AtomicOrdering::Release);
@@ -475,6 +513,7 @@ typedef struct {
475
513
void (*fptr)(void ); // if the argument is a constant pointer
476
514
const char *f_name; // if the symbol name is known
477
515
const char *f_lib; // if a library name is specified
516
+ jl_value_t *lib_expr; // expression to compute library path lazily
478
517
jl_value_t *gcroot;
479
518
} native_sym_arg_t ;
480
519
@@ -488,6 +527,24 @@ static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_va
488
527
489
528
jl_value_t *ptr = static_eval (ctx, arg);
490
529
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
+ }
491
548
jl_cgval_t arg1 = emit_expr (ctx, arg);
492
549
jl_value_t *ptr_ty = arg1.typ ;
493
550
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
586
643
jl_printf (JL_STDERR," WARNING: literal address used in cglobal for %s; code cannot be statically compiled\n " , sym.f_name );
587
644
}
588
645
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 );
591
651
res = ctx.builder .CreatePtrToInt (res, lrt);
592
652
}
593
653
else {
@@ -597,7 +657,7 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg
597
657
if (!libsym || !jl_dlsym (libsym, sym.f_name , &symaddr, 0 )) {
598
658
// Error mode, either the library or the symbol couldn't be find during compiletime.
599
659
// 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 );
601
661
res = ctx.builder .CreatePtrToInt (res, lrt);
602
662
} else {
603
663
// since we aren't saving this code, there's no sense in
@@ -1737,11 +1797,14 @@ jl_cgval_t function_sig_t::emit_a_ccall(
1737
1797
else {
1738
1798
assert (symarg.f_name != NULL );
1739
1799
PointerType *funcptype = PointerType::get (functype, 0 );
1740
- if (imaging_mode) {
1800
+ if (symarg.lib_expr ) {
1801
+ llvmf = runtime_sym_lookup (ctx, funcptype, NULL , symarg.lib_expr , symarg.f_name , ctx.f );
1802
+ }
1803
+ else if (imaging_mode) {
1741
1804
// vararg requires musttail,
1742
1805
// but musttail is incompatible with noreturn.
1743
1806
if (functype->isVarArg ())
1744
- llvmf = runtime_sym_lookup (ctx, funcptype, symarg.f_lib , symarg.f_name , ctx.f );
1807
+ llvmf = runtime_sym_lookup (ctx, funcptype, symarg.f_lib , NULL , symarg.f_name , ctx.f );
1745
1808
else
1746
1809
llvmf = emit_plt (ctx, functype, attributes, cc, symarg.f_lib , symarg.f_name );
1747
1810
}
@@ -1751,7 +1814,7 @@ jl_cgval_t function_sig_t::emit_a_ccall(
1751
1814
if (!libsym || !jl_dlsym (libsym, symarg.f_name , &symaddr, 0 )) {
1752
1815
// either the library or the symbol could not be found, place a runtime
1753
1816
// lookup here instead.
1754
- llvmf = runtime_sym_lookup (ctx, funcptype, symarg.f_lib , symarg.f_name , ctx.f );
1817
+ llvmf = runtime_sym_lookup (ctx, funcptype, symarg.f_lib , NULL , symarg.f_name , ctx.f );
1755
1818
} else {
1756
1819
// since we aren't saving this code, there's no sense in
1757
1820
// putting anything complicated here: just JIT the function address
0 commit comments