Skip to content

Commit eb3ed5e

Browse files
authored
module: Prepare usings array for world age partition (JuliaLang#55357)
This is a relatively independent part of the bindings partition branch, extending the module usings list to gain `min_world` and `max_world` `size_t`s. These are always `0` and `(size_t)-1` respectively in this PR, which handles the GC and serialization implications of this change. The semantic part will come later.
1 parent afb65fa commit eb3ed5e

File tree

7 files changed

+83
-42
lines changed

7 files changed

+83
-42
lines changed

src/gc-debug.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,8 @@ int gc_slot_to_arrayidx(void *obj, void *_slot) JL_NOTSAFEPOINT
11251125
if (vt == jl_module_type) {
11261126
jl_module_t *m = (jl_module_t*)obj;
11271127
start = (char*)m->usings.items;
1128-
len = m->usings.len;
1128+
len = module_usings_length(m);
1129+
elsize = sizeof(struct _jl_module_using);
11291130
}
11301131
else if (vt == jl_simplevector_type) {
11311132
start = (char*)jl_svec_data(obj);

src/gc-stock.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -2053,16 +2053,18 @@ STATIC_INLINE void gc_mark_module_binding(jl_ptls_t ptls, jl_module_t *mb_parent
20532053
gc_heap_snapshot_record_module_to_binding(mb_parent, bindings, bindingkeyset);
20542054
gc_assert_parent_validity((jl_value_t *)mb_parent, (jl_value_t *)mb_parent->parent);
20552055
gc_try_claim_and_push(mq, (jl_value_t *)mb_parent->parent, &nptr);
2056-
size_t nusings = mb_parent->usings.len;
2056+
size_t nusings = module_usings_length(mb_parent);
20572057
if (nusings > 0) {
20582058
// this is only necessary because bindings for "using" modules
20592059
// are added only when accessed. therefore if a module is replaced
20602060
// after "using" it but before accessing it, this array might
20612061
// contain the only reference.
20622062
jl_value_t *obj_parent = (jl_value_t *)mb_parent;
2063-
jl_value_t **objary_begin = (jl_value_t **)mb_parent->usings.items;
2064-
jl_value_t **objary_end = objary_begin + nusings;
2065-
gc_mark_objarray(ptls, obj_parent, objary_begin, objary_end, 1, nptr);
2063+
struct _jl_module_using *objary_begin = (struct _jl_module_using *)mb_parent->usings.items;
2064+
struct _jl_module_using *objary_end = objary_begin + nusings;
2065+
static_assert(sizeof(struct _jl_module_using) == 3*sizeof(void *), "Mismatch in _jl_module_using size");
2066+
static_assert(offsetof(struct _jl_module_using, mod) == 0, "Expected `mod` at the beginning of _jl_module_using");
2067+
gc_mark_objarray(ptls, obj_parent, (jl_value_t**)objary_begin, (jl_value_t**)objary_end, 3, nptr);
20662068
}
20672069
else {
20682070
gc_mark_push_remset(ptls, (jl_value_t *)mb_parent, nptr);
@@ -2175,7 +2177,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_
21752177
if (update_meta)
21762178
gc_setmark(ptls, o, bits, sizeof(jl_module_t));
21772179
jl_module_t *mb_parent = (jl_module_t *)new_obj;
2178-
uintptr_t nptr = ((mb_parent->usings.len + 1) << 2) | (bits & GC_OLD);
2180+
uintptr_t nptr = ((module_usings_length(mb_parent) + 1) << 2) | (bits & GC_OLD);
21792181
gc_mark_module_binding(ptls, mb_parent, nptr, bits);
21802182
}
21812183
else if (vtag == jl_task_tag << 4) {

src/julia.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ typedef struct _jl_module_t {
714714
jl_sym_t *file;
715715
int32_t line;
716716
// hidden fields:
717-
arraylist_t usings; // modules with all bindings potentially imported
717+
arraylist_t usings; /* arraylist of struct jl_module_using */ // modules with all bindings potentially imported
718718
jl_uuid_t build_id;
719719
jl_uuid_t uuid;
720720
_Atomic(uint32_t) counter;
@@ -728,6 +728,12 @@ typedef struct _jl_module_t {
728728
intptr_t hash;
729729
} jl_module_t;
730730

731+
struct _jl_module_using {
732+
jl_module_t *mod;
733+
size_t min_world;
734+
size_t max_world;
735+
};
736+
731737
struct _jl_globalref_t {
732738
JL_DATA_TYPE
733739
jl_module_t *mod;

src/julia_internal.h

+22
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,28 @@ void jl_eval_global_expr(jl_module_t *m, jl_expr_t *ex, int set_type);
819819
JL_DLLEXPORT void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type);
820820
JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *m, jl_value_t *e, int fast, int expanded, const char **toplevel_filename, int *toplevel_lineno);
821821

822+
STATIC_INLINE struct _jl_module_using *module_usings_getidx(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT;
823+
STATIC_INLINE jl_module_t *module_usings_getmod(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT;
824+
825+
#ifndef __clang_gcanalyzer__
826+
// The analyzer doesn't like looking through the arraylist, so just model the
827+
// access for it using this function
828+
STATIC_INLINE struct _jl_module_using *module_usings_getidx(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT {
829+
return (struct _jl_module_using *)&(m->usings.items[3*i]);
830+
}
831+
STATIC_INLINE jl_module_t *module_usings_getmod(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT {
832+
return module_usings_getidx(m, i)->mod;
833+
}
834+
#endif
835+
836+
STATIC_INLINE size_t module_usings_length(jl_module_t *m) JL_NOTSAFEPOINT {
837+
return m->usings.len/3;
838+
}
839+
840+
STATIC_INLINE size_t module_usings_max(jl_module_t *m) JL_NOTSAFEPOINT {
841+
return m->usings.max/3;
842+
}
843+
822844
jl_value_t *jl_eval_global_var(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *e);
823845
jl_value_t *jl_interpret_opaque_closure(jl_opaque_closure_t *clos, jl_value_t **args, size_t nargs);
824846
jl_value_t *jl_interpret_toplevel_thunk(jl_module_t *m, jl_code_info_t *src);

src/module.c

+15-22
Original file line numberDiff line numberDiff line change
@@ -373,16 +373,6 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_
373373
return b;
374374
}
375375

376-
static inline jl_module_t *module_usings_getidx(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT;
377-
378-
#ifndef __clang_gcanalyzer__
379-
// The analyzer doesn't like looking through the arraylist, so just model the
380-
// access for it using this function
381-
static inline jl_module_t *module_usings_getidx(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT {
382-
return (jl_module_t*)m->usings.items[i];
383-
}
384-
#endif
385-
386376
static int eq_bindings(jl_binding_partition_t *owner, jl_binding_t *alias, size_t world)
387377
{
388378
jl_ptr_kind_union_t owner_pku = jl_atomic_load_relaxed(&owner->restriction);
@@ -407,11 +397,11 @@ static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl
407397
jl_binding_partition_t *bpart = NULL;
408398
jl_module_t *owner = NULL;
409399
JL_LOCK(&m->lock);
410-
int i = (int)m->usings.len - 1;
400+
int i = (int)module_usings_length(m) - 1;
411401
JL_UNLOCK(&m->lock);
412402
for (; i >= 0; --i) {
413403
JL_LOCK(&m->lock);
414-
jl_module_t *imp = module_usings_getidx(m, i);
404+
jl_module_t *imp = module_usings_getmod(m, i);
415405
JL_UNLOCK(&m->lock);
416406
jl_binding_t *tempb = jl_get_module_binding(imp, var, 0);
417407
if (tempb != NULL && tempb->exportp) {
@@ -746,19 +736,24 @@ JL_DLLEXPORT void jl_module_use_as(jl_module_t *to, jl_module_t *from, jl_sym_t
746736
module_import_(to, from, asname, s, 0);
747737
}
748738

749-
750739
JL_DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from)
751740
{
752741
if (to == from)
753742
return;
754743
JL_LOCK(&to->lock);
755-
for (size_t i = 0; i < to->usings.len; i++) {
756-
if (from == to->usings.items[i]) {
744+
for (size_t i = 0; i < module_usings_length(to); i++) {
745+
if (from == module_usings_getmod(to, i)) {
757746
JL_UNLOCK(&to->lock);
758747
return;
759748
}
760749
}
761-
arraylist_push(&to->usings, from);
750+
struct _jl_module_using new_item = {
751+
.mod = from,
752+
.min_world = 0,
753+
.max_world = (size_t)-1
754+
};
755+
arraylist_grow(&to->usings, sizeof(struct _jl_module_using)/sizeof(void*));
756+
memcpy(&to->usings.items[to->usings.len-3], &new_item, sizeof(struct _jl_module_using));
762757
jl_gc_wb(to, from);
763758
JL_UNLOCK(&to->lock);
764759

@@ -1096,12 +1091,12 @@ JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod
10961091
JL_DLLEXPORT jl_value_t *jl_module_usings(jl_module_t *m)
10971092
{
10981093
JL_LOCK(&m->lock);
1099-
int j = m->usings.len;
1094+
int j = module_usings_length(m);
11001095
jl_array_t *a = jl_alloc_array_1d(jl_array_any_type, j);
11011096
JL_GC_PUSH1(&a);
11021097
for (int i = 0; j > 0; i++) {
11031098
j--;
1104-
jl_module_t *imp = (jl_module_t*)m->usings.items[i];
1099+
jl_module_t *imp = module_usings_getmod(m, i);
11051100
jl_array_ptr_set(a, j, (jl_value_t*)imp);
11061101
}
11071102
JL_UNLOCK(&m->lock); // may gc
@@ -1156,10 +1151,8 @@ JL_DLLEXPORT jl_value_t *jl_module_names(jl_module_t *m, int all, int imported,
11561151
if (usings) {
11571152
// If `usings` is specified, traverse the list of `using`-ed modules and incorporate
11581153
// the names exported by those modules into the list.
1159-
for(int i=(int)m->usings.len-1; i >= 0; --i) {
1160-
jl_module_t *usinged = module_usings_getidx(m, i);
1161-
append_exported_names(a, usinged, all);
1162-
}
1154+
for (int i = module_usings_length(m)-1; i >= 0; i--)
1155+
append_exported_names(a, module_usings_getmod(m, i), all);
11631156
}
11641157
JL_GC_POP();
11651158
return (jl_value_t*)a;

src/staticdata.c

+29-12
Original file line numberDiff line numberDiff line change
@@ -811,8 +811,8 @@ static void jl_queue_module_for_serialization(jl_serializer_state *s, jl_module_
811811
}
812812
}
813813

814-
for (size_t i = 0; i < m->usings.len; i++) {
815-
jl_queue_for_serialization(s, (jl_value_t*)m->usings.items[i]);
814+
for (size_t i = 0; i < module_usings_length(m); i++) {
815+
jl_queue_for_serialization(s, module_usings_getmod(m, i));
816816
}
817817
}
818818

@@ -1266,27 +1266,44 @@ static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t
12661266
// write out the usings list
12671267
memset(&newm->usings._space, 0, sizeof(newm->usings._space));
12681268
if (m->usings.items == &m->usings._space[0]) {
1269-
newm->usings.items = (void**)offsetof(jl_module_t, usings._space);
1269+
// Push these relocations here, to keep them in order. This pairs with the `newm->usings.items = ` below.
12701270
arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings.items)));
12711271
arraylist_push(&s->relocs_list, (void*)(((uintptr_t)DataRef << RELOC_TAG_OFFSET) + item));
12721272
size_t i;
1273-
for (i = 0; i < m->usings.len; i++) {
1274-
arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings._space[i])));
1275-
arraylist_push(&s->relocs_list, (void*)backref_id(s, m->usings._space[i], s->link_ids_relocs));
1273+
for (i = 0; i < module_usings_length(m); i++) {
1274+
struct _jl_module_using *newm_data = module_usings_getidx(newm, i);
1275+
struct _jl_module_using *data = module_usings_getidx(m, i);
1276+
// TODO: Remove dead entries
1277+
newm_data->min_world = data->min_world;
1278+
newm_data->max_world = data->max_world;
1279+
if (s->incremental) {
1280+
if (data->max_world != (size_t)-1)
1281+
newm_data->max_world = 0;
1282+
newm_data->min_world = 0;
1283+
}
1284+
arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings._space[3*i])));
1285+
arraylist_push(&s->relocs_list, (void*)backref_id(s, data->mod, s->link_ids_relocs));
12761286
}
1287+
newm->usings.items = (void**)offsetof(jl_module_t, usings._space);
12771288
}
12781289
else {
12791290
newm->usings.items = (void**)tot;
12801291
arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings.items)));
12811292
arraylist_push(&s->relocs_list, (void*)(((uintptr_t)DataRef << RELOC_TAG_OFFSET) + item));
12821293
size_t i;
1283-
for (i = 0; i < m->usings.len; i++) {
1284-
write_pointerfield(s, (jl_value_t*)m->usings.items[i]);
1285-
tot += sizeof(void*);
1286-
}
1287-
for (; i < m->usings.max; i++) {
1294+
for (i = 0; i < module_usings_length(m); i++) {
1295+
struct _jl_module_using *data = module_usings_getidx(m, i);
1296+
write_pointerfield(s, (jl_value_t*)data->mod);
1297+
write_uint(s->s, data->min_world);
1298+
write_uint(s->s, data->max_world);
1299+
static_assert(sizeof(struct _jl_module_using) == 3*sizeof(void*), "_jl_module_using mismatch");
1300+
tot += sizeof(struct _jl_module_using);
1301+
}
1302+
for (; i < module_usings_max(m); i++) {
12881303
write_pointer(s->s);
1289-
tot += sizeof(void*);
1304+
write_uint(s->s, 0);
1305+
write_uint(s->s, 0);
1306+
tot += sizeof(struct _jl_module_using);
12901307
}
12911308
}
12921309
assert(ios_pos(s->s) - reloc_offset == tot);

test/clangsa/MissingRoots.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ void scopes() {
328328
jl_module_t *propagation(jl_module_t *m JL_PROPAGATES_ROOT);
329329
void module_member(jl_module_t *m)
330330
{
331-
for(int i=(int)m->usings.len-1; i >= 0; --i) {
331+
for(int i=(int)m->usings.len-1; i >= 0; i -= 3) {
332332
jl_module_t *imp = propagation(m);
333333
jl_gc_safepoint();
334334
look_at_value((jl_value_t*)imp);

0 commit comments

Comments
 (0)