Skip to content

Commit 4167322

Browse files
vtjnashKristofferC
authored andcommitted
fix breakage with jl_get_global (#58540)
Introduce a new `jl_get_global_value` to do the new world-aware behavior, while preserving the old behavior for `jl_get_global`. Choose between `jl_get_global`, `jl_get_global_value`, and `jl_eval_global_var`, depending on what behavior is required. Also take this opportunity to fix some data race mistakes introduced by bindings (relaxed loads of jl_world_counter outside of assert) and lacking type asserts / unnecessary globals in precompile code. Fix #58097 Addresses post-review comment #57213 (comment), so this is already tested against by existing logic (cherry picked from commit 965d007)
1 parent 6ab22e4 commit 4167322

17 files changed

+140
-126
lines changed

base/loading.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,7 +2213,7 @@ const include_callbacks = Any[]
22132213

22142214
# used to optionally track dependencies when requiring a module:
22152215
const _concrete_dependencies = Pair{PkgId,UInt128}[] # these dependency versions are "set in stone", because they are explicitly loaded, and the process should try to avoid invalidating them
2216-
const _require_dependencies = Any[] # a list of (mod, abspath, fsize, hash, mtime) tuples that are the file dependencies of the module currently being precompiled
2216+
const _require_dependencies = Any[] # a list of (mod::Module, abspath::String, fsize::UInt64, hash::UInt32, mtime::Float64) tuples that are the file dependencies of the module currently being precompiled
22172217
const _track_dependencies = Ref(false) # set this to true to track the list of file dependencies
22182218

22192219
function _include_dependency(mod::Module, _path::AbstractString; track_content::Bool=true,
@@ -2239,9 +2239,9 @@ function _include_dependency!(dep_list::Vector{Any}, track_dependencies::Bool,
22392239
else
22402240
@lock require_lock begin
22412241
if track_content
2242-
hash = isdir(path) ? _crc32c(join(readdir(path))) : open(_crc32c, path, "r")
2242+
hash = (isdir(path) ? _crc32c(join(readdir(path))) : open(_crc32c, path, "r"))::UInt32
22432243
# use mtime=-1.0 here so that fsize==0 && mtime==0.0 corresponds to a missing include_dependency
2244-
push!(dep_list, (mod, path, filesize(path), hash, -1.0))
2244+
push!(dep_list, (mod, path, UInt64(filesize(path)), hash, -1.0))
22452245
else
22462246
push!(dep_list, (mod, path, UInt64(0), UInt32(0), mtime(path)))
22472247
end
@@ -3337,7 +3337,7 @@ mutable struct CacheHeaderIncludes
33373337
const modpath::Vector{String} # seemingly not needed in Base, but used by Revise
33383338
end
33393339

3340-
function CacheHeaderIncludes(dep_tuple::Tuple{Module, String, Int64, UInt32, Float64})
3340+
function CacheHeaderIncludes(dep_tuple::Tuple{Module, String, UInt64, UInt32, Float64})
33413341
return CacheHeaderIncludes(PkgId(dep_tuple[1]), dep_tuple[2:end]..., String[])
33423342
end
33433343

src/ast.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,7 @@ jl_value_t *jl_parse(const char *text, size_t text_len, jl_value_t *filename,
14091409
{
14101410
jl_value_t *core_parse = NULL;
14111411
if (jl_core_module) {
1412-
core_parse = jl_get_global(jl_core_module, jl_symbol("_parse"));
1412+
core_parse = jl_get_global_value(jl_core_module, jl_symbol("_parse"));
14131413
}
14141414
if (!core_parse || core_parse == jl_nothing) {
14151415
// In bootstrap, directly call the builtin parser.

src/gf.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -504,12 +504,13 @@ JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t w
504504
ct->world_age = jl_typeinf_world;
505505
jl_value_t **fargs;
506506
JL_GC_PUSHARGS(fargs, 4);
507-
jl_module_t *CC = (jl_module_t*)jl_get_global(jl_core_module, jl_symbol("Compiler"));
507+
jl_module_t *CC = (jl_module_t*)jl_get_global_value(jl_core_module, jl_symbol("Compiler"));
508508
if (CC != NULL && jl_is_module(CC)) {
509-
fargs[0] = jl_get_global(CC, jl_symbol("NativeInterpreter"));;
509+
JL_GC_PROMISE_ROOTED(CC);
510+
fargs[0] = jl_get_global_value(CC, jl_symbol("NativeInterpreter"));;
510511
fargs[1] = jl_box_ulong(world);
511512
fargs[1] = jl_apply(fargs, 2);
512-
fargs[0] = jl_get_global(CC, jl_symbol("typeinf_code"));
513+
fargs[0] = jl_get_global_value(CC, jl_symbol("typeinf_code"));
513514
fargs[2] = (jl_value_t*)mi;
514515
fargs[3] = jl_true;
515516
ci = (jl_code_info_t*)jl_apply(fargs, 4);

src/init.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NOTSAFEPOINT_ENTER
251251
if (jl_base_module) {
252252
size_t last_age = ct->world_age;
253253
ct->world_age = jl_get_world_counter();
254-
jl_value_t *f = jl_get_global(jl_base_module, jl_symbol("_atexit"));
254+
jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_atexit"));
255255
if (f != NULL) {
256256
jl_value_t **fargs;
257257
JL_GC_PUSHARGS(fargs, 2);
@@ -357,13 +357,14 @@ JL_DLLEXPORT void jl_postoutput_hook(void)
357357

358358
if (jl_base_module) {
359359
jl_task_t *ct = jl_get_current_task();
360-
jl_value_t *f = jl_get_global(jl_base_module, jl_symbol("_postoutput"));
360+
size_t last_age = ct->world_age;
361+
ct->world_age = jl_get_world_counter();
362+
jl_value_t *f = jl_get_global_value(jl_base_module, jl_symbol("_postoutput"));
361363
if (f != NULL) {
362364
JL_TRY {
363-
size_t last_age = ct->world_age;
364-
ct->world_age = jl_get_world_counter();
365+
JL_GC_PUSH1(&f);
365366
jl_apply(&f, 1);
366-
ct->world_age = last_age;
367+
JL_GC_POP();
367368
}
368369
JL_CATCH {
369370
jl_printf((JL_STREAM*)STDERR_FILENO, "\npostoutput hook threw an error: ");
@@ -372,6 +373,7 @@ JL_DLLEXPORT void jl_postoutput_hook(void)
372373
jlbacktrace(); // written to STDERR_FILENO
373374
}
374375
}
376+
ct->world_age = last_age;
375377
}
376378
return;
377379
}
@@ -594,7 +596,6 @@ static NOINLINE void _finish_jl_init_(jl_image_buf_t sysimage, jl_ptls_t ptls, j
594596
jl_init_primitives();
595597
jl_init_main_module();
596598
jl_load(jl_core_module, "boot.jl");
597-
jl_current_task->world_age = jl_atomic_load_acquire(&jl_world_counter);
598599
post_boot_hooks();
599600
}
600601

@@ -607,7 +608,6 @@ static NOINLINE void _finish_jl_init_(jl_image_buf_t sysimage, jl_ptls_t ptls, j
607608
jl_n_threads_per_pool[JL_THREADPOOL_ID_INTERACTIVE] = 0;
608609
jl_n_threads_per_pool[JL_THREADPOOL_ID_DEFAULT] = 1;
609610
} else {
610-
jl_current_task->world_age = jl_atomic_load_acquire(&jl_world_counter);
611611
post_image_load_hooks();
612612
}
613613
jl_start_threads();

src/interpreter.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,14 +162,16 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state
162162
return result;
163163
}
164164

165+
// get the global (throwing if null) in the current world
165166
jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e)
166167
{
167-
jl_value_t *v = jl_get_global(m, e);
168+
jl_value_t *v = jl_get_global_value(m, e);
168169
if (v == NULL)
169170
jl_undefined_var_error(e, (jl_value_t*)m);
170171
return v;
171172
}
172173

174+
// get the global (throwing if null) in the current world, optimized
173175
jl_value_t *jl_eval_globalref(jl_globalref_t *g)
174176
{
175177
jl_value_t *v = jl_get_globalref_value(g);

src/jl_uv.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@ static void jl_uv_call_close_callback(jl_value_t *val)
160160
{
161161
jl_value_t **args;
162162
JL_GC_PUSHARGS(args, 2); // val is "rooted" in the finalizer list only right now
163-
args[0] = jl_get_global(jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module),
163+
args[0] = jl_eval_global_var(
164+
jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module),
164165
jl_symbol("_uv_hook_close")); // topmod(typeof(val))._uv_hook_close
165166
args[1] = val;
166-
assert(args[0]);
167167
jl_apply(args, 2); // TODO: wrap in try-catch?
168168
JL_GC_POP();
169169
}

src/jlapi.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,12 +951,14 @@ static NOINLINE int true_main(int argc, char *argv[])
951951
ct->world_age = jl_get_world_counter();
952952

953953
jl_function_t *start_client = jl_base_module ?
954-
(jl_function_t*)jl_get_global(jl_base_module, jl_symbol("_start")) : NULL;
954+
(jl_function_t*)jl_get_global_value(jl_base_module, jl_symbol("_start")) : NULL;
955955

956956
if (start_client) {
957957
int ret = 1;
958958
JL_TRY {
959+
JL_GC_PUSH1(&start_client);
959960
jl_value_t *r = jl_apply(&start_client, 1);
961+
JL_GC_POP();
960962
if (jl_typeof(r) != (jl_value_t*)jl_int32_type)
961963
jl_type_error("typeassert", (jl_value_t*)jl_int32_type, r);
962964
ret = jl_unbox_int32(r);

src/julia.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,7 @@ JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var);
21152115
JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr);
21162116
JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr);
21172117
JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var);
2118+
JL_DLLEXPORT jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var);
21182119
JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT);
21192120
JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT);
21202121
void jl_set_initial_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT, int exported);
@@ -2720,12 +2721,7 @@ JL_DLLEXPORT jl_task_t *jl_get_current_task(void) JL_GLOBALLY_ROOTED JL_NOTSAFEP
27202721

27212722
STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name)
27222723
{
2723-
jl_task_t *ct = jl_get_current_task();
2724-
size_t last_world = ct->world_age;
2725-
ct->world_age = jl_get_world_counter();
2726-
jl_value_t *r = jl_get_global(m, jl_symbol(name));
2727-
ct->world_age = last_world;
2728-
return (jl_function_t*)r;
2724+
return (jl_function_t*)jl_get_global(m, jl_symbol(name));
27292725
}
27302726

27312727
// TODO: we need to pin the task while using this (set pure bit)

src/module.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_maybe_reresolve_implicit(jl_binding_t *b
366366

367367
JL_DLLEXPORT void jl_update_loaded_bpart(jl_binding_t *b, jl_binding_partition_t *bpart)
368368
{
369-
struct implicit_search_resolution resolution = jl_resolve_implicit_import(b, NULL, jl_atomic_load_relaxed(&jl_world_counter), 0);
369+
struct implicit_search_resolution resolution = jl_resolve_implicit_import(b, NULL, jl_atomic_load_acquire(&jl_world_counter), 0);
370370
jl_atomic_store_relaxed(&bpart->min_world, resolution.min_world);
371371
jl_atomic_store_relaxed(&bpart->max_world, resolution.max_world);
372372
bpart->restriction = resolution.binding_or_const;
@@ -831,11 +831,12 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT,
831831
// return module of binding
832832
JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var)
833833
{
834+
size_t world = jl_current_task->world_age;
834835
jl_binding_t *b = jl_get_module_binding(m, var, 1);
835-
jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
836-
jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age);
836+
jl_binding_partition_t *bpart = jl_get_binding_partition(b, world);
837+
jl_walk_binding_inplace(&b, &bpart, world);
837838
if (jl_binding_kind(bpart) == PARTITION_KIND_IMPLICIT_CONST) {
838-
struct implicit_search_resolution resolution = jl_resolve_implicit_import(b, NULL, jl_current_task->world_age, 0);
839+
struct implicit_search_resolution resolution = jl_resolve_implicit_import(b, NULL, world, 0);
839840
if (!resolution.debug_only_ultimate_binding)
840841
jl_error("Constant binding was imported from multiple modules");
841842
b = resolution.debug_only_ultimate_binding;
@@ -885,16 +886,17 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_in_world(jl_binding_t *b, size_t w
885886
return jl_atomic_load_relaxed(&b->value);
886887
}
887888

888-
JL_DLLEXPORT jl_value_t *jl_get_binding_value_depwarn(jl_binding_t *b)
889+
static jl_value_t *jl_get_binding_value_depwarn(jl_binding_t *b, size_t world)
889890
{
890-
jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
891+
jl_binding_partition_t *bpart = jl_get_binding_partition(b, world);
891892
if (jl_options.depwarn) {
892893
int needs_depwarn = 0;
893-
jl_walk_binding_inplace_depwarn(&b, &bpart, jl_current_task->world_age, &needs_depwarn);
894+
jl_walk_binding_inplace_depwarn(&b, &bpart, world, &needs_depwarn);
894895
if (needs_depwarn)
895896
jl_binding_deprecation_warning(b);
896-
} else {
897-
jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age);
897+
}
898+
else {
899+
jl_walk_binding_inplace(&b, &bpart, world);
898900
}
899901
enum jl_partition_kind kind = jl_binding_kind(bpart);
900902
if (jl_bkind_is_some_guard(kind))
@@ -907,11 +909,11 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_depwarn(jl_binding_t *b)
907909
return jl_atomic_load_relaxed(&b->value);
908910
}
909911

910-
911912
JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b)
912913
{
913-
jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
914-
jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age);
914+
size_t world = jl_current_task->world_age;
915+
jl_binding_partition_t *bpart = jl_get_binding_partition(b, world);
916+
jl_walk_binding_inplace(&b, &bpart, world);
915917
enum jl_partition_kind kind = jl_binding_kind(bpart);
916918
if (jl_bkind_is_some_guard(kind))
917919
return NULL;
@@ -926,7 +928,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b)
926928
JL_DLLEXPORT jl_value_t *jl_get_latest_binding_value_if_const(jl_binding_t *b)
927929
{
928930
// See note below. Note that this is for some deprecated uses, and should not be added to new code.
929-
size_t world = jl_atomic_load_relaxed(&jl_world_counter);
931+
size_t world = jl_atomic_load_acquire(&jl_world_counter);
930932
jl_binding_partition_t *bpart = jl_get_binding_partition(b, world);
931933
jl_walk_binding_inplace(&b, &bpart, world);
932934
enum jl_partition_kind kind = jl_binding_kind(bpart);
@@ -1535,18 +1537,27 @@ JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m, jl_sym_t *var,
15351537
}
15361538

15371539

1540+
// get the value (or null) in the current world
15381541
JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr)
15391542
{
15401543
jl_binding_t *b = gr->binding;
15411544
if (!b)
15421545
b = jl_get_module_binding(gr->mod, gr->name, 1);
1543-
return jl_get_binding_value_depwarn(b);
1546+
return jl_get_binding_value_depwarn(b, jl_current_task->world_age);
1547+
}
1548+
1549+
// get the value (or null) in the current world
1550+
JL_DLLEXPORT jl_value_t *jl_get_global_value(jl_module_t *m, jl_sym_t *var)
1551+
{
1552+
jl_binding_t *b = jl_get_module_binding(m, var, 1);
1553+
return jl_get_binding_value_depwarn(b, jl_current_task->world_age);
15441554
}
15451555

1556+
// get the global (or null) in the latest world
15461557
JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m, jl_sym_t *var)
15471558
{
15481559
jl_binding_t *b = jl_get_module_binding(m, var, 1);
1549-
return jl_get_binding_value_depwarn(b);
1560+
return jl_get_binding_value_depwarn(b, jl_atomic_load_acquire(&jl_world_counter));
15501561
}
15511562

15521563
JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT)

src/precompile.c

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,30 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) {
3636
// char*: src text
3737
// At the end we write int32(0) as a terminal sentinel.
3838
size_t len = jl_array_nrows(udeps);
39-
static jl_value_t *replace_depot_func = NULL;
40-
if (!replace_depot_func)
41-
replace_depot_func = jl_get_global(jl_base_module, jl_symbol("replace_depot_path"));
42-
static jl_value_t *normalize_depots_func = NULL;
43-
if (!normalize_depots_func)
44-
normalize_depots_func = jl_get_global(jl_base_module, jl_symbol("normalize_depots_for_relocation"));
4539
ios_t srctext;
46-
jl_value_t *deptuple = NULL, *depots = NULL;
47-
JL_GC_PUSH3(&deptuple, &udeps, &depots);
40+
jl_value_t *replace_depot_func = NULL;
41+
jl_value_t *normalize_depots_func = NULL;
42+
jl_value_t *deptuple = NULL;
43+
jl_value_t *depots = NULL;
4844
jl_task_t *ct = jl_current_task;
4945
size_t last_age = ct->world_age;
5046
ct->world_age = jl_atomic_load_acquire(&jl_world_counter);
47+
JL_GC_PUSH4(&deptuple, &depots, &replace_depot_func, &normalize_depots_func);
48+
replace_depot_func = jl_eval_global_var(jl_base_module, jl_symbol("replace_depot_path"));
49+
normalize_depots_func = jl_eval_global_var(jl_base_module, jl_symbol("normalize_depots_for_relocation"));
5150
depots = jl_apply(&normalize_depots_func, 1);
52-
ct->world_age = last_age;
51+
jl_datatype_t *deptuple_p[5] = {jl_module_type, jl_string_type, jl_uint64_type, jl_uint32_type, jl_float64_type};
52+
jl_value_t *jl_deptuple_type = jl_apply_tuple_type_v((jl_value_t**)deptuple_p, 5);
53+
JL_GC_PROMISE_ROOTED(jl_deptuple_type);
54+
#define jl_is_deptuple(v) (jl_typeis((v), jl_deptuple_type))
5355
for (size_t i = 0; i < len; i++) {
5456
deptuple = jl_array_ptr_ref(udeps, i);
55-
jl_value_t *depmod = jl_fieldref(deptuple, 0); // module
57+
jl_value_t *depmod = jl_fieldref_noalloc(deptuple, 0); // module
5658
// Dependencies declared with `include_dependency` are excluded
5759
// because these may not be Julia code (and could be huge)
60+
JL_TYPECHK(write_srctext, deptuple, deptuple);
5861
if (depmod != (jl_value_t*)jl_main_module) {
59-
jl_value_t *abspath = jl_fieldref(deptuple, 1); // file abspath
62+
jl_value_t *abspath = jl_fieldref_noalloc(deptuple, 1); // file abspath
6063
const char *abspathstr = jl_string_data(abspath);
6164
if (!abspathstr[0])
6265
continue;
@@ -67,17 +70,11 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) {
6770
continue;
6871
}
6972

70-
jl_value_t **replace_depot_args;
71-
JL_GC_PUSHARGS(replace_depot_args, 3);
73+
jl_value_t *replace_depot_args[3];
7274
replace_depot_args[0] = replace_depot_func;
7375
replace_depot_args[1] = abspath;
7476
replace_depot_args[2] = depots;
75-
jl_task_t *ct = jl_current_task;
76-
size_t last_age = ct->world_age;
77-
ct->world_age = jl_atomic_load_acquire(&jl_world_counter);
7877
jl_value_t *depalias = (jl_value_t*)jl_apply(replace_depot_args, 3);
79-
ct->world_age = last_age;
80-
JL_GC_POP();
8178

8279
size_t slen = jl_string_len(depalias);
8380
write_int32(f, slen);
@@ -91,6 +88,8 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) {
9188
ios_seek_end(f);
9289
}
9390
}
91+
ct->world_age = last_age;
92+
#undef jl_is_deptuple
9493
JL_GC_POP();
9594
}
9695
write_int32(f, 0); // mark the end of the source text

0 commit comments

Comments
 (0)