Skip to content

Commit a7a09e3

Browse files
committed
bpart: Skip implicit import revalidation if using'd export set is unchanged
When loading a pkgimage, the new bpart validation code needs to check if the export set of any using'd packages differs from what it would have been during precompile. This could e.g. happen if somebody (or Revise) eval'd a new `export` statement into a package that was `using`'d. However, this case is somewhat rare, so let's optimize it by keeping a bit in `Module` that keeps track of whether anything like that has happened and if not skipping the revalidation. This slightly improves pkgimage load time in the ordinary case. More optimizations to follow.
1 parent b27a24a commit a7a09e3

File tree

4 files changed

+50
-23
lines changed

4 files changed

+50
-23
lines changed

src/julia.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,8 @@ typedef struct _jl_module_t {
770770
int8_t infer;
771771
uint8_t istopmod;
772772
int8_t max_methods;
773+
// If cleared no binding partition in this module has BINDING_FLAG_EXPORTED and min_world > jl_require_world.
774+
_Atomic(int8_t) export_set_changed_since_require_world;
773775
jl_mutex_t lock;
774776
intptr_t hash;
775777
} jl_module_t;

src/julia_internal.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,7 @@ extern JL_DLLEXPORT jl_module_t *jl_precompile_toplevel_module JL_GLOBALLY_ROOTE
923923
extern jl_genericmemory_t *jl_global_roots_list JL_GLOBALLY_ROOTED;
924924
extern jl_genericmemory_t *jl_global_roots_keyset JL_GLOBALLY_ROOTED;
925925
extern arraylist_t *jl_entrypoint_mis;
926+
JL_DLLEXPORT extern size_t jl_require_world;
926927
JL_DLLEXPORT int jl_is_globally_rooted(jl_value_t *val JL_MAYBE_UNROOTED) JL_NOTSAFEPOINT;
927928
JL_DLLEXPORT jl_value_t *jl_as_global_root(jl_value_t *val, int insert) JL_GLOBALLY_ROOTED;
928929
extern jl_svec_t *precompile_field_replace JL_GLOBALLY_ROOTED;
@@ -938,6 +939,14 @@ STATIC_INLINE int jl_bkind_is_some_import(enum jl_partition_kind kind) JL_NOTSAF
938939
return kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_EXPLICIT || kind == BINDING_KIND_IMPORTED;
939940
}
940941

942+
STATIC_INLINE int jl_bkind_is_some_guard(enum jl_partition_kind kind) JL_NOTSAFEPOINT {
943+
return kind == BINDING_KIND_FAILED || kind == BINDING_KIND_GUARD;
944+
}
945+
946+
STATIC_INLINE int jl_bkind_is_some_implicit(enum jl_partition_kind kind) JL_NOTSAFEPOINT {
947+
return kind == BINDING_KIND_IMPLICIT || jl_bkind_is_some_guard(kind);
948+
}
949+
941950
STATIC_INLINE int jl_bkind_is_some_constant(enum jl_partition_kind kind) JL_NOTSAFEPOINT {
942951
return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_UNDEF_CONST || kind == BINDING_KIND_BACKDATED_CONST;
943952
}
@@ -946,10 +955,6 @@ STATIC_INLINE int jl_bkind_is_defined_constant(enum jl_partition_kind kind) JL_N
946955
return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_BACKDATED_CONST;
947956
}
948957

949-
STATIC_INLINE int jl_bkind_is_some_guard(enum jl_partition_kind kind) JL_NOTSAFEPOINT {
950-
return kind == BINDING_KIND_FAILED || kind == BINDING_KIND_GUARD;
951-
}
952-
953958
JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world) JL_GLOBALLY_ROOTED;
954959
JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_GLOBALLY_ROOTED;
955960

src/module.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -899,10 +899,7 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *asname,
899899
size_t new_world = jl_atomic_load_acquire(&jl_world_counter)+1;
900900
jl_binding_partition_t *btopart = jl_get_binding_partition(bto, new_world);
901901
enum jl_partition_kind btokind = jl_binding_kind(btopart);
902-
if (btokind == BINDING_KIND_GUARD ||
903-
btokind == BINDING_KIND_IMPLICIT ||
904-
btokind == BINDING_KIND_FAILED) {
905-
902+
if (jl_bkind_is_some_implicit(btokind)) {
906903
jl_binding_partition_t *new_bpart = jl_replace_binding_locked(bto, btopart, (jl_value_t*)b, (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT, new_world);
907904
if (jl_atomic_load_relaxed(&new_bpart->max_world) == ~(size_t)0)
908905
jl_add_binding_backedge(b, (jl_value_t*)bto);
@@ -1006,7 +1003,7 @@ JL_DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from)
10061003
if (tob) {
10071004
jl_binding_partition_t *tobpart = jl_get_binding_partition(tob, new_world);
10081005
enum jl_partition_kind kind = jl_binding_kind(tobpart);
1009-
if (kind == BINDING_KIND_IMPLICIT || jl_bkind_is_some_guard(kind)) {
1006+
if (jl_bkind_is_some_implicit(kind)) {
10101007
jl_replace_binding_locked(tob, tobpart, NULL, BINDING_KIND_IMPLICIT_RECOMPUTE, new_world);
10111008
}
10121009
}
@@ -1284,6 +1281,10 @@ JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding_locked2(jl_binding_t *b,
12841281
jl_atomic_store_relaxed(&new_bpart->next, old_bpart);
12851282
jl_gc_wb_fresh(new_bpart, old_bpart);
12861283

1284+
if (((old_bpart->kind & BINDING_FLAG_EXPORTED) || (kind & BINDING_FLAG_EXPORTED)) && jl_require_world != ~(size_t)0) {
1285+
jl_atomic_store_release(&b->globalref->mod->export_set_changed_since_require_world, 1);
1286+
}
1287+
12871288
jl_atomic_store_release(&b->partitions, new_bpart);
12881289
jl_gc_wb(b, new_bpart);
12891290
JL_GC_POP();

src/staticdata.c

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,10 @@ static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t
13941394
}
13951395
}
13961396
assert(ios_pos(s->s) - reloc_offset == tot);
1397+
1398+
// After reload, everything that has happened in this process happened semantically at
1399+
// (for .incremental) or before jl_require_world, so reset this flag.
1400+
jl_atomic_store_relaxed(&newm->export_set_changed_since_require_world, 0);
13971401
}
13981402

13991403
static void record_memoryref(jl_serializer_state *s, size_t reloc_offset, jl_genericmemoryref_t ref) {
@@ -3537,32 +3541,31 @@ extern void export_jl_small_typeof(void);
35373541
int IMAGE_NATIVE_CODE_TAINTED = 0;
35383542

35393543
// TODO: This should possibly be in Julia
3540-
static void jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_t *bpart, size_t mod_idx)
3544+
static int jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_t *bpart, size_t mod_idx, int unchanged_implicit)
35413545
{
3542-
35433546
if (jl_atomic_load_relaxed(&bpart->max_world) != ~(size_t)0)
3544-
return;
3547+
return 1;
35453548
size_t raw_kind = bpart->kind;
35463549
enum jl_partition_kind kind = (enum jl_partition_kind)(raw_kind & 0x0f);
3547-
if (!jl_bkind_is_some_import(kind))
3548-
return;
3549-
jl_binding_t *imported_binding = (jl_binding_t*)bpart->restriction;
3550-
jl_binding_partition_t *latest_imported_bpart = jl_atomic_load_relaxed(&imported_binding->partitions);
3551-
if (!latest_imported_bpart)
3552-
return;
3553-
if (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_FAILED) {
3550+
if (!unchanged_implicit && jl_bkind_is_some_implicit(kind)) {
35543551
jl_check_new_binding_implicit(bpart, b, NULL, jl_atomic_load_relaxed(&jl_world_counter));
35553552
bpart->kind |= (raw_kind & 0xf0);
35563553
if (bpart->min_world > jl_require_world)
35573554
goto invalidated;
35583555
}
3556+
if (!jl_bkind_is_some_import(kind))
3557+
return 1;
3558+
jl_binding_t *imported_binding = (jl_binding_t*)bpart->restriction;
3559+
jl_binding_partition_t *latest_imported_bpart = jl_atomic_load_relaxed(&imported_binding->partitions);
3560+
if (!latest_imported_bpart)
3561+
return 1;
35593562
if (latest_imported_bpart->min_world <= bpart->min_world) {
35603563
// Imported binding is still valid
35613564
if ((kind == BINDING_KIND_EXPLICIT || kind == BINDING_KIND_IMPORTED) &&
35623565
external_blob_index((jl_value_t*)imported_binding) != mod_idx) {
35633566
jl_add_binding_backedge(imported_binding, (jl_value_t*)b);
35643567
}
3565-
return;
3568+
return 1;
35663569
}
35673570
else {
35683571
// Binding partition was invalidated
@@ -3580,13 +3583,14 @@ static void jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_
35803583
jl_binding_t *bedge = (jl_binding_t*)edge;
35813584
if (!jl_atomic_load_relaxed(&bedge->partitions))
35823585
continue;
3583-
jl_validate_binding_partition(bedge, jl_atomic_load_relaxed(&bedge->partitions), mod_idx);
3586+
jl_validate_binding_partition(bedge, jl_atomic_load_relaxed(&bedge->partitions), mod_idx, 0);
35843587
}
35853588
}
35863589
if (bpart->kind & BINDING_FLAG_EXPORTED) {
35873590
jl_module_t *mod = b->globalref->mod;
35883591
jl_sym_t *name = b->globalref->name;
35893592
JL_LOCK(&mod->lock);
3593+
jl_atomic_store_release(&mod->export_set_changed_since_require_world, 1);
35903594
if (mod->usings_backedges) {
35913595
for (size_t i = 0; i < jl_array_len(mod->usings_backedges); i++) {
35923596
jl_module_t *edge = (jl_module_t*)jl_array_ptr_ref(mod->usings_backedges, i);
@@ -3596,12 +3600,24 @@ static void jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_
35963600
if (!jl_atomic_load_relaxed(&importee->partitions))
35973601
continue;
35983602
JL_UNLOCK(&mod->lock);
3599-
jl_validate_binding_partition(importee, jl_atomic_load_relaxed(&importee->partitions), mod_idx);
3603+
jl_validate_binding_partition(importee, jl_atomic_load_relaxed(&importee->partitions), mod_idx, 0);
36003604
JL_LOCK(&mod->lock);
36013605
}
36023606
}
36033607
JL_UNLOCK(&mod->lock);
3608+
return 0;
36043609
}
3610+
return 1;
3611+
}
3612+
3613+
static int all_usings_unchanged_implicit(jl_module_t *mod)
3614+
{
3615+
int unchanged_implicit = 1;
3616+
for (size_t i = 0; unchanged_implicit && i < module_usings_length(mod); i++) {
3617+
jl_module_t *usee = module_usings_getmod(mod, i);
3618+
unchanged_implicit &= !jl_atomic_load_acquire(&usee->export_set_changed_since_require_world);
3619+
}
3620+
return unchanged_implicit;
36053621
}
36063622

36073623
static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl_array_t *depmods, uint64_t checksum,
@@ -4063,12 +4079,15 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl
40634079
jl_module_t *mod = (jl_module_t*)obj;
40644080
size_t mod_idx = external_blob_index((jl_value_t*)mod);
40654081
jl_svec_t *table = jl_atomic_load_relaxed(&mod->bindings);
4082+
int unchanged_implicit = all_usings_unchanged_implicit(mod);
40664083
for (size_t i = 0; i < jl_svec_len(table); i++) {
40674084
jl_binding_t *b = (jl_binding_t*)jl_svecref(table, i);
40684085
if ((jl_value_t*)b == jl_nothing)
40694086
continue;
40704087
jl_binding_partition_t *bpart = jl_atomic_load_relaxed(&b->partitions);
4071-
jl_validate_binding_partition(b, bpart, mod_idx);
4088+
if (!jl_validate_binding_partition(b, bpart, mod_idx, unchanged_implicit)) {
4089+
unchanged_implicit = all_usings_unchanged_implicit(mod);
4090+
}
40724091
}
40734092
}
40744093
}

0 commit comments

Comments
 (0)