Skip to content

Commit 1bf4b64

Browse files
committed
fall back to run time lookup when compiled code needs to access a global
that cannot be found yet. fixes #7864
1 parent 4c7bb25 commit 1bf4b64

File tree

4 files changed

+55
-29
lines changed

4 files changed

+55
-29
lines changed

src/cgutils.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -507,15 +507,21 @@ static Value *literal_pointer_val(jl_binding_t *p)
507507
return julia_gv("jl_bnd#", p->name, p->owner, p);
508508
}
509509

510+
static Value *julia_binding_gv(Value *bv)
511+
{
512+
return builder.
513+
CreateGEP(bv,ConstantInt::get(T_size,
514+
offsetof(jl_binding_t,value)/sizeof(size_t)));
515+
}
516+
510517
static Value *julia_binding_gv(jl_binding_t *b)
511518
{
512519
// emit a literal_pointer_val to the value field of a jl_binding_t
513520
// binding->value are prefixed with *
514521
Value *bv = imaging_mode ?
515522
builder.CreateBitCast(julia_gv("*", b->name, b->owner, b), jl_ppvalue_llvmt) :
516523
literal_static_pointer_val(b,jl_ppvalue_llvmt);
517-
return builder.CreateGEP(bv,ConstantInt::get(T_size,
518-
offsetof(jl_binding_t,value)/sizeof(size_t)));
524+
return julia_binding_gv(bv);
519525
}
520526

521527
// --- mapping between julia and llvm types ---

src/codegen.cpp

+42-22
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ static Function *jlvboundserror_func;
283283
static Function *jlboundserrorv_func;
284284
static Function *jlcheckassign_func;
285285
static Function *jldeclareconst_func;
286+
static Function *jlgetbinding_func;
286287
static Function *jltopeval_func;
287288
static Function *jlcopyast_func;
288289
static Function *jltuple_func;
@@ -571,7 +572,7 @@ static int is_global(jl_sym_t *s, jl_codectx_t *ctx);
571572
static Value *make_gcroot(Value *v, jl_codectx_t *ctx, jl_sym_t *var = NULL);
572573
static Value *emit_boxed_rooted(jl_value_t *e, jl_codectx_t *ctx);
573574
static Value *global_binding_pointer(jl_module_t *m, jl_sym_t *s,
574-
jl_binding_t **pbnd, bool assign);
575+
jl_binding_t **pbnd, bool assign, jl_codectx_t *ctx);
575576
static Value *emit_checked_var(Value *bp, jl_sym_t *name, jl_codectx_t *ctx, bool isvol=false);
576577
static bool might_need_root(jl_value_t *ex);
577578
static Value *emit_condition(jl_value_t *cond, const std::string &msg, jl_codectx_t *ctx);
@@ -1763,7 +1764,7 @@ static Value *emit_getfield(jl_value_t *expr, jl_sym_t *name, jl_codectx_t *ctx)
17631764

17641765
if (jl_is_module(expr)) {
17651766
Value *bp =
1766-
global_binding_pointer((jl_module_t*)expr, name, NULL, false);
1767+
global_binding_pointer((jl_module_t*)expr, name, NULL, false, ctx);
17671768
// todo: use type info to avoid undef check
17681769
return emit_checked_var(bp, name, ctx);
17691770
}
@@ -2663,16 +2664,39 @@ static int is_global(jl_sym_t *s, jl_codectx_t *ctx)
26632664
return (it == ctx->vars.end());
26642665
}
26652666

2667+
static void undef_var_error_if_null(Value *v, jl_sym_t *name, jl_codectx_t *ctx)
2668+
{
2669+
Value *ok = builder.CreateICmpNE(v, V_null);
2670+
BasicBlock *err = BasicBlock::Create(getGlobalContext(), "err", ctx->f);
2671+
BasicBlock *ifok = BasicBlock::Create(getGlobalContext(), "ok");
2672+
builder.CreateCondBr(ok, ifok, err);
2673+
builder.SetInsertPoint(err);
2674+
builder.CreateCall(prepare_call(jlundefvarerror_func), literal_pointer_val((jl_value_t*)name));
2675+
builder.CreateUnreachable();
2676+
ctx->f->getBasicBlockList().push_back(ifok);
2677+
builder.SetInsertPoint(ifok);
2678+
}
2679+
26662680
static Value *global_binding_pointer(jl_module_t *m, jl_sym_t *s,
2667-
jl_binding_t **pbnd, bool assign)
2681+
jl_binding_t **pbnd, bool assign, jl_codectx_t *ctx)
26682682
{
26692683
jl_binding_t *b=NULL;
2670-
if (!assign)
2671-
b = jl_get_binding(m, s);
2672-
// if b is NULL, this might be a global that is not set yet but will be,
2673-
// so get a pointer for writing even when not assigning.
2674-
if (assign || b==NULL)
2684+
if (assign) {
26752685
b = jl_get_binding_wr(m, s);
2686+
assert(b != NULL);
2687+
}
2688+
else {
2689+
b = jl_get_binding(m, s);
2690+
if (b == NULL) {
2691+
// var not found. switch to delayed lookup.
2692+
// TODO: examine performance of this
2693+
Value *bval = builder.CreateCall2(prepare_call(jlgetbinding_func),
2694+
literal_pointer_val((jl_value_t*)m),
2695+
literal_pointer_val((jl_value_t*)s));
2696+
undef_var_error_if_null(bval, s, ctx);
2697+
return julia_binding_gv(builder.CreateBitCast(bval,jl_ppvalue_llvmt));
2698+
}
2699+
}
26762700
if (pbnd) *pbnd = b;
26772701
return julia_binding_gv(b);
26782702
}
@@ -2693,7 +2717,7 @@ static Value *var_binding_pointer(jl_sym_t *s, jl_binding_t **pbnd,
26932717
s = jl_symbolnode_sym(s);
26942718
assert(jl_is_symbol(s));
26952719
if (is_global(s, ctx)) {
2696-
return global_binding_pointer(ctx->module, s, pbnd, assign);
2720+
return global_binding_pointer(ctx->module, s, pbnd, assign, ctx);
26972721
}
26982722
jl_varinfo_t &vi = ctx->vars[s];
26992723
if (vi.closureidx != -1) {
@@ -2726,17 +2750,8 @@ static Value *emit_checked_var(Value *bp, jl_sym_t *name, jl_codectx_t *ctx, boo
27262750
// in unreachable code, there might be a poorly-typed instance of a variable
27272751
// that has a concrete type everywhere it's actually used. tolerate this
27282752
// situation by just skipping the NULL check if it wouldn't be valid. (issue #7836)
2729-
if (v->getType() == jl_pvalue_llvmt) {
2730-
Value *ok = builder.CreateICmpNE(v, V_null);
2731-
BasicBlock *err = BasicBlock::Create(getGlobalContext(), "err", ctx->f);
2732-
BasicBlock *ifok = BasicBlock::Create(getGlobalContext(), "ok");
2733-
builder.CreateCondBr(ok, ifok, err);
2734-
builder.SetInsertPoint(err);
2735-
builder.CreateCall(prepare_call(jlundefvarerror_func), literal_pointer_val((jl_value_t*)name));
2736-
builder.CreateUnreachable();
2737-
ctx->f->getBasicBlockList().push_back(ifok);
2738-
builder.SetInsertPoint(ifok);
2739-
}
2753+
if (v->getType() == jl_pvalue_llvmt)
2754+
undef_var_error_if_null(v, name, ctx);
27402755
return v;
27412756
}
27422757

@@ -2761,8 +2776,7 @@ static Value *emit_var(jl_sym_t *sym, jl_value_t *ty, jl_codectx_t *ctx, bool is
27612776
Value *bp = var_binding_pointer(sym, &jbp, false, ctx);
27622777
if (bp == NULL)
27632778
return NULL;
2764-
assert(jbp != NULL);
2765-
if (jbp->value != NULL) {
2779+
if (jbp && jbp->value != NULL) {
27662780
if (jbp->constp) {
27672781
if (!isboxed && jl_isbits(jl_typeof(jbp->value)))
27682782
return emit_unboxed(jbp->value, ctx);
@@ -5111,6 +5125,12 @@ static void init_julia_llvm_env(Module *m)
51115125
"jl_declare_constant", m);
51125126
add_named_global(jldeclareconst_func, (void*)&jl_declare_constant);
51135127

5128+
jlgetbinding_func =
5129+
Function::Create(FunctionType::get(jl_pvalue_llvmt, args_2ptrs, false),
5130+
Function::ExternalLinkage,
5131+
"jl_get_binding", m);
5132+
add_named_global(jlgetbinding_func, (void*)&jl_get_binding);
5133+
51145134
builtin_func_map[jl_f_is] = jlcall_func_to_llvm("jl_f_is", (void*)&jl_f_is, m);
51155135
builtin_func_map[jl_f_typeof] = jlcall_func_to_llvm("jl_f_typeof", (void*)&jl_f_typeof, m);
51165136
builtin_func_map[jl_f_sizeof] = jlcall_func_to_llvm("jl_f_sizeof", (void*)&jl_f_sizeof, m);

src/julia.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -1078,8 +1078,8 @@ DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name);
10781078
// get binding for reading
10791079
DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m, jl_sym_t *var);
10801080
// get binding for assignment
1081-
jl_binding_t *jl_get_binding_wr(jl_module_t *m, jl_sym_t *var);
1082-
jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var);
1081+
DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m, jl_sym_t *var);
1082+
DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var);
10831083
DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var);
10841084
DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var);
10851085
DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var);

src/module.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ static jl_binding_t *new_binding(jl_sym_t *name)
7979
}
8080

8181
// get binding for assignment
82-
jl_binding_t *jl_get_binding_wr(jl_module_t *m, jl_sym_t *var)
82+
DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m, jl_sym_t *var)
8383
{
8484
jl_binding_t **bp = (jl_binding_t**)ptrhash_bp(&m->bindings, var);
8585
jl_binding_t *b;
@@ -118,7 +118,7 @@ DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var)
118118
// get binding for adding a method
119119
// like jl_get_binding_wr, but uses existing imports instead of warning
120120
// and overwriting.
121-
jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var)
121+
DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var)
122122
{
123123
jl_binding_t **bp = (jl_binding_t**)ptrhash_bp(&m->bindings, var);
124124
jl_binding_t *b = *bp;
@@ -207,7 +207,7 @@ static jl_binding_t *jl_get_binding_(jl_module_t *m, jl_sym_t *var, modstack_t *
207207
return b;
208208
}
209209

210-
jl_binding_t *jl_get_binding(jl_module_t *m, jl_sym_t *var)
210+
DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m, jl_sym_t *var)
211211
{
212212
return jl_get_binding_(m, var, NULL);
213213
}

0 commit comments

Comments
 (0)