From 9e2cd24714a6d4a0efa8dc0530da9ec9f54c96a1 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 14 Jan 2021 18:01:47 -0500 Subject: [PATCH] staticdata: fix unreferenced data assertion (#39246) Need to sequence operations correctly here. We need to first finish marking referenced data before we start deleting unreferenced data. This otherwise can lead to an assertion failure in some situations. Refs #37650 --- src/staticdata.c | 49 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/staticdata.c b/src/staticdata.c index 9b599c0ff1a7f..5a67ebd7eb313 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -1425,22 +1425,25 @@ static void jl_finalize_deserializer(jl_serializer_state *s) JL_GC_DISABLED -// --- helper functions --- - -// remove cached types not referenced in the stream -static int keep_type_cache_entry(jl_value_t *ti) +static void jl_scan_type_cache_gv(jl_serializer_state *s, jl_svec_t *cache) { - if (ptrhash_get(&backref_table, ti) != HT_NOTFOUND || jl_get_llvm_gv(native_functions, ti) != 0) - return 1; - if (jl_is_datatype(ti)) { - jl_value_t *singleton = ((jl_datatype_t*)ti)->instance; - if (singleton && (ptrhash_get(&backref_table, singleton) != HT_NOTFOUND || - jl_get_llvm_gv(native_functions, singleton) != 0)) - return 1; - } - return 0; + size_t l = jl_svec_len(cache), i; + for (i = 0; i < l; i++) { + jl_value_t *ti = jl_svecref(cache, i); + if (ti == NULL || ti == jl_nothing) + continue; + if (jl_get_llvm_gv(native_functions, ti)) { + jl_serialize_value(s, ti); + } + else if (jl_is_datatype(ti)) { + jl_value_t *singleton = ((jl_datatype_t*)ti)->instance; + if (singleton && jl_get_llvm_gv(native_functions, singleton)) + jl_serialize_value(s, ti); + } + } } +// remove cached types not referenced in the stream static void jl_prune_type_cache_hash(jl_svec_t *cache) { size_t l = jl_svec_len(cache), i; @@ -1448,7 +1451,7 @@ static void jl_prune_type_cache_hash(jl_svec_t *cache) jl_value_t *ti = jl_svecref(cache, i); if (ti == NULL || ti == jl_nothing) continue; - if (!keep_type_cache_entry(ti)) + if (ptrhash_get(&backref_table, ti) == HT_NOTFOUND) jl_svecset(cache, i, jl_nothing); } } @@ -1460,7 +1463,7 @@ static void jl_prune_type_cache_linear(jl_svec_t *cache) jl_value_t *ti = jl_svecref(cache, i); if (ti == NULL) break; - if (keep_type_cache_entry(ti)) + if (ptrhash_get(&backref_table, ti) != HT_NOTFOUND) jl_svecset(cache, ins++, ti); } if (i > ins) { @@ -1526,14 +1529,28 @@ static void jl_save_system_image_to_stream(ios_t *f) JL_GC_DISABLED jl_value_t *tag = *tags[i]; jl_serialize_value(&s, tag); } - // prune unused entries from built-in type caches + // step 1.1: check for values only found in the generated code + arraylist_t typenames; + arraylist_new(&typenames, 0); for (i = 0; i < backref_table.size; i += 2) { jl_typename_t *tn = (jl_typename_t*)backref_table.table[i]; if (tn == HT_NOTFOUND || !jl_is_typename(tn)) continue; + arraylist_push(&typenames, tn); + } + for (i = 0; i < typenames.len; i++) { + jl_typename_t *tn = (jl_typename_t*)typenames.items[i]; + jl_scan_type_cache_gv(&s, tn->cache); + jl_scan_type_cache_gv(&s, tn->linearcache); + } + // step 1.2: prune (garbage collect) some special weak references from + // built-in type caches + for (i = 0; i < typenames.len; i++) { + jl_typename_t *tn = (jl_typename_t*)typenames.items[i]; jl_prune_type_cache_hash(tn->cache); jl_prune_type_cache_linear(tn->linearcache); } + arraylist_free(&typenames); } { // step 2: build all the sysimg sections