diff options
Diffstat (limited to 'src/pdumper.c')
-rw-r--r-- | src/pdumper.c | 300 |
1 files changed, 177 insertions, 123 deletions
diff --git a/src/pdumper.c b/src/pdumper.c index ba318605773..ac8bf6f31f4 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -1226,7 +1226,7 @@ dump_queue_dequeue (struct dump_queue *dump_queue, dump_off basis) dump_tailq_length (&dump_queue->zero_weight_objects), dump_tailq_length (&dump_queue->one_weight_normal_objects), dump_tailq_length (&dump_queue->one_weight_strong_objects), - XHASH_TABLE (dump_queue->link_weights)->count); + (ptrdiff_t) XHASH_TABLE (dump_queue->link_weights)->count); static const int nr_candidates = 3; struct candidate @@ -1331,13 +1331,7 @@ dump_queue_dequeue (struct dump_queue *dump_queue, dump_off basis) static bool dump_object_needs_dumping_p (Lisp_Object object) { - /* Some objects, like symbols, are self-representing because they - have invariant bit patterns, but sometimes these objects have - associated data too, and these data-carrying objects need to be - included in the dump despite all references to them being - bitwise-invariant. */ - return (!dump_object_self_representing_p (object) - || dump_object_emacs_ptr (object)); + return !(FIXNUMP (object)); } static void @@ -1864,11 +1858,10 @@ dump_field_lv_or_rawptr (struct dump_context *ctx, /* Set a pointer field on an output object during dump. - CTX is the dump context. OFFSET is the offset at which the current - object starts. OUT is a pointer to the dump output object. - IN_START is the start of the current Emacs object. IN_FIELD is a - pointer to the field in that object. TYPE is the type of pointer - to which IN_FIELD points. + CTX is the dump context. OUT is a pointer to the dump output + object. IN_START is the start of the current Emacs object. + IN_FIELD is a pointer to the field in that object. TYPE is the + type of pointer to which IN_FIELD points. */ static void dump_field_lv_rawptr (struct dump_context *ctx, @@ -1883,8 +1876,7 @@ dump_field_lv_rawptr (struct dump_context *ctx, /* Set a Lisp_Object field on an output object during dump. - CTX is a dump context. OFFSET is the offset at which the current - object starts. OUT is a pointer to the dump output object. + CTX is a dump context. OUT is a pointer to the dump output object. IN_START is the start of the current Emacs object. IN_FIELD is a pointer to a Lisp_Object field in that object. @@ -2646,73 +2638,88 @@ dump_vectorlike_generic (struct dump_context *ctx, return offset; } -/* Return a vector of KEY, VALUE pairs in the given hash table H. The - first H->count pairs are valid, and the rest are unbound. */ -static Lisp_Object +/* Return a vector of KEY, VALUE pairs in the given hash table H. + No room for growth is included. */ +static Lisp_Object * hash_table_contents (struct Lisp_Hash_Table *h) { - if (h->test.hashfn == hashfn_user_defined) - error ("cannot dump hash tables with user-defined tests"); /* Bug#36769 */ - - ptrdiff_t size = HASH_TABLE_SIZE (h); - Lisp_Object key_and_value = make_uninit_vector (2 * size); + ptrdiff_t size = h->count; + Lisp_Object *key_and_value = hash_table_alloc_bytes (2 * size + * sizeof *key_and_value); ptrdiff_t n = 0; - /* Make sure key_and_value ends up in the same order; charset.c - relies on it by expecting hash table indices to stay constant - across the dump. */ - for (ptrdiff_t i = 0; i < size; i++) - if (!NILP (HASH_HASH (h, i))) - { - ASET (key_and_value, n++, HASH_KEY (h, i)); - ASET (key_and_value, n++, HASH_VALUE (h, i)); - } - - while (n < 2 * size) + DOHASH (h, k, v) { - ASET (key_and_value, n++, Qunbound); - ASET (key_and_value, n++, Qnil); + key_and_value[n++] = k; + key_and_value[n++] = v; } return key_and_value; } -static dump_off +static void dump_hash_table_list (struct dump_context *ctx) { if (!NILP (ctx->hash_tables)) - return dump_object (ctx, CALLN (Fapply, Qvector, ctx->hash_tables)); - else - return 0; + dump_object (ctx, CALLN (Fvconcat, ctx->hash_tables)); } +static hash_table_std_test_t +hash_table_std_test (const struct hash_table_test *t) +{ + if (BASE_EQ (t->name, Qeq)) + return Test_eq; + if (BASE_EQ (t->name, Qeql)) + return Test_eql; + if (BASE_EQ (t->name, Qequal)) + return Test_equal; + error ("cannot dump hash tables with user-defined tests"); /* Bug#36769 */ +} + +/* Compact contents and discard inessential information from a hash table, + preparing it for dumping. + See `hash_table_thaw' for the code that restores the object to a usable + state. */ static void hash_table_freeze (struct Lisp_Hash_Table *h) { - ptrdiff_t npairs = ASIZE (h->key_and_value) / 2; h->key_and_value = hash_table_contents (h); - h->next = h->hash = make_fixnum (npairs); - h->index = make_fixnum (ASIZE (h->index)); - h->next_free = (npairs == h->count ? -1 : h->count); + h->next = NULL; + h->hash = NULL; + h->index = NULL; + h->table_size = 0; + h->index_bits = 0; + h->frozen_test = hash_table_std_test (h->test); + h->test = NULL; } -static void -hash_table_thaw (Lisp_Object hash) +static dump_off +dump_hash_table_contents (struct dump_context *ctx, struct Lisp_Hash_Table *h) { - struct Lisp_Hash_Table *h = XHASH_TABLE (hash); - h->hash = make_nil_vector (XFIXNUM (h->hash)); - h->next = Fmake_vector (h->next, make_fixnum (-1)); - h->index = Fmake_vector (h->index, make_fixnum (-1)); + dump_align_output (ctx, DUMP_ALIGNMENT); + dump_off start_offset = ctx->offset; + ptrdiff_t n = 2 * h->count; - hash_table_rehash (hash); + struct dump_flags old_flags = ctx->flags; + ctx->flags.pack_objects = true; + + for (ptrdiff_t i = 0; i < n; i++) + { + Lisp_Object out; + const Lisp_Object *slot = &h->key_and_value[i]; + dump_object_start (ctx, &out, sizeof out); + dump_field_lv (ctx, &out, slot, slot, WEIGHT_STRONG); + dump_object_finish (ctx, &out, sizeof out); + } + + ctx->flags = old_flags; + return start_offset; } static dump_off -dump_hash_table (struct dump_context *ctx, - Lisp_Object object, - dump_off offset) +dump_hash_table (struct dump_context *ctx, Lisp_Object object) { -#if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_6D63EDB618 +#if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_0360833954 # error "Lisp_Hash_Table changed. See CHECK_STRUCTS comment in config.h." #endif const struct Lisp_Hash_Table *hash_in = XHASH_TABLE (object); @@ -2724,30 +2731,72 @@ dump_hash_table (struct dump_context *ctx, START_DUMP_PVEC (ctx, &hash->header, struct Lisp_Hash_Table, out); dump_pseudovector_lisp_fields (ctx, &out->header, &hash->header); - /* TODO: dump the hash bucket vectors synchronously here to keep - them as close to the hash table as possible. */ DUMP_FIELD_COPY (out, hash, count); - DUMP_FIELD_COPY (out, hash, next_free); + DUMP_FIELD_COPY (out, hash, weakness); DUMP_FIELD_COPY (out, hash, purecopy); DUMP_FIELD_COPY (out, hash, mutable); - DUMP_FIELD_COPY (out, hash, rehash_threshold); - DUMP_FIELD_COPY (out, hash, rehash_size); - dump_field_lv (ctx, out, hash, &hash->key_and_value, WEIGHT_STRONG); - dump_field_lv (ctx, out, hash, &hash->test.name, WEIGHT_STRONG); - dump_field_lv (ctx, out, hash, &hash->test.user_hash_function, - WEIGHT_STRONG); - dump_field_lv (ctx, out, hash, &hash->test.user_cmp_function, - WEIGHT_STRONG); - dump_field_emacs_ptr (ctx, out, hash, &hash->test.cmpfn); - dump_field_emacs_ptr (ctx, out, hash, &hash->test.hashfn); + DUMP_FIELD_COPY (out, hash, frozen_test); + if (hash->key_and_value) + dump_field_fixup_later (ctx, out, hash, &hash->key_and_value); eassert (hash->next_weak == NULL); - return finish_dump_pvec (ctx, &out->header); + dump_off offset = finish_dump_pvec (ctx, &out->header); + if (hash->key_and_value) + dump_remember_fixup_ptr_raw + (ctx, + offset + dump_offsetof (struct Lisp_Hash_Table, key_and_value), + dump_hash_table_contents (ctx, hash)); + return offset; +} + +static dump_off +dump_obarray_buckets (struct dump_context *ctx, const struct Lisp_Obarray *o) +{ + dump_align_output (ctx, DUMP_ALIGNMENT); + dump_off start_offset = ctx->offset; + ptrdiff_t n = obarray_size (o); + + struct dump_flags old_flags = ctx->flags; + ctx->flags.pack_objects = true; + + for (ptrdiff_t i = 0; i < n; i++) + { + Lisp_Object out; + const Lisp_Object *slot = &o->buckets[i]; + dump_object_start (ctx, &out, sizeof out); + dump_field_lv (ctx, &out, slot, slot, WEIGHT_STRONG); + dump_object_finish (ctx, &out, sizeof out); + } + + ctx->flags = old_flags; + return start_offset; +} + +static dump_off +dump_obarray (struct dump_context *ctx, Lisp_Object object) +{ +#if CHECK_STRUCTS && !defined HASH_Lisp_Obarray_D2757E61AD +# error "Lisp_Obarray changed. See CHECK_STRUCTS comment in config.h." +#endif + const struct Lisp_Obarray *in_oa = XOBARRAY (object); + struct Lisp_Obarray munged_oa = *in_oa; + struct Lisp_Obarray *oa = &munged_oa; + START_DUMP_PVEC (ctx, &oa->header, struct Lisp_Obarray, out); + dump_pseudovector_lisp_fields (ctx, &out->header, &oa->header); + DUMP_FIELD_COPY (out, oa, count); + DUMP_FIELD_COPY (out, oa, size_bits); + dump_field_fixup_later (ctx, out, oa, &oa->buckets); + dump_off offset = finish_dump_pvec (ctx, &out->header); + dump_remember_fixup_ptr_raw + (ctx, + offset + dump_offsetof (struct Lisp_Obarray, buckets), + dump_obarray_buckets (ctx, oa)); + return offset; } static dump_off dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer) { -#if CHECK_STRUCTS && !defined HASH_buffer_EB0A5191C5 +#if CHECK_STRUCTS && !defined HASH_buffer_B02F648B82 # error "buffer changed. See CHECK_STRUCTS comment in config.h." #endif struct buffer munged_buffer = *in_buffer; @@ -2759,6 +2808,7 @@ dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer) else eassert (buffer->window_count == -1); buffer->local_minor_modes_ = Qnil; + buffer->last_name_ = Qnil; buffer->last_selected_window_ = Qnil; buffer->display_count_ = make_fixnum (0); buffer->clip_changed = 0; @@ -2908,17 +2958,17 @@ dump_subr (struct dump_context *ctx, const struct Lisp_Subr *subr) dump_object_start (ctx, &out, sizeof (out)); DUMP_FIELD_COPY (&out, subr, header.size); #ifdef HAVE_NATIVE_COMP - bool native_comp = !NILP (subr->native_comp_u); + bool non_primitive = !NILP (subr->native_comp_u); #else - bool native_comp = false; + bool non_primitive = false; #endif - if (native_comp) + if (non_primitive) out.function.a0 = NULL; else dump_field_emacs_ptr (ctx, &out, subr, &subr->function.a0); DUMP_FIELD_COPY (&out, subr, min_args); DUMP_FIELD_COPY (&out, subr, max_args); - if (native_comp) + if (non_primitive) { dump_field_fixup_later (ctx, &out, subr, &subr->symbol_name); dump_remember_cold_op (ctx, @@ -2943,7 +2993,7 @@ dump_subr (struct dump_context *ctx, const struct Lisp_Subr *subr) dump_field_lv (ctx, &out, subr, &subr->type, WEIGHT_NORMAL); #endif dump_off subr_off = dump_object_finish (ctx, &out, sizeof (out)); - if (native_comp && ctx->flags.dump_object_contents) + if (non_primitive && ctx->flags.dump_object_contents) /* We'll do the final addr relocation during VERY_LATE_RELOCS time after the compilation units has been loaded. */ dump_push (&ctx->dump_relocs[VERY_LATE_RELOCS], @@ -3000,7 +3050,7 @@ dump_vectorlike (struct dump_context *ctx, Lisp_Object lv, dump_off offset) { -#if CHECK_STRUCTS && !defined HASH_pvec_type_D8A254BC70 +#if CHECK_STRUCTS && !defined HASH_pvec_type_2D583AC566 # error "pvec_type changed. See CHECK_STRUCTS comment in config.h." #endif const struct Lisp_Vector *v = XVECTOR (lv); @@ -3026,7 +3076,9 @@ dump_vectorlike (struct dump_context *ctx, case PVEC_BOOL_VECTOR: return dump_bool_vector(ctx, v); case PVEC_HASH_TABLE: - return dump_hash_table (ctx, lv, offset); + return dump_hash_table (ctx, lv); + case PVEC_OBARRAY: + return dump_obarray (ctx, lv); case PVEC_BUFFER: return dump_buffer (ctx, XBUFFER (lv)); case PVEC_SUBR: @@ -3205,37 +3257,42 @@ dump_object_for_offset (struct dump_context *ctx, Lisp_Object object) static dump_off dump_charset (struct dump_context *ctx, int cs_i) { -#if CHECK_STRUCTS && !defined (HASH_charset_317C49E291) +#if CHECK_STRUCTS && !defined (HASH_charset_E31F4B5D96) # error "charset changed. See CHECK_STRUCTS comment in config.h." #endif - dump_align_output (ctx, alignof (struct charset)); + /* We can't change the alignment here, because ctx->offset is what + will be used for the whole array. */ + eassert (ctx->offset % alignof (struct charset) == 0); const struct charset *cs = charset_table + cs_i; struct charset out; dump_object_start (ctx, &out, sizeof (out)); - DUMP_FIELD_COPY (&out, cs, id); - DUMP_FIELD_COPY (&out, cs, hash_index); - DUMP_FIELD_COPY (&out, cs, dimension); - memcpy (out.code_space, &cs->code_space, sizeof (cs->code_space)); - if (cs_i < charset_table_used && cs->code_space_mask) - dump_field_fixup_later (ctx, &out, cs, &cs->code_space_mask); - DUMP_FIELD_COPY (&out, cs, code_linear_p); - DUMP_FIELD_COPY (&out, cs, iso_chars_96); - DUMP_FIELD_COPY (&out, cs, ascii_compatible_p); - DUMP_FIELD_COPY (&out, cs, supplementary_p); - DUMP_FIELD_COPY (&out, cs, compact_codes_p); - DUMP_FIELD_COPY (&out, cs, unified_p); - DUMP_FIELD_COPY (&out, cs, iso_final); - DUMP_FIELD_COPY (&out, cs, iso_revision); - DUMP_FIELD_COPY (&out, cs, emacs_mule_id); - DUMP_FIELD_COPY (&out, cs, method); - DUMP_FIELD_COPY (&out, cs, min_code); - DUMP_FIELD_COPY (&out, cs, max_code); - DUMP_FIELD_COPY (&out, cs, char_index_offset); - DUMP_FIELD_COPY (&out, cs, min_char); - DUMP_FIELD_COPY (&out, cs, max_char); - DUMP_FIELD_COPY (&out, cs, invalid_code); - memcpy (out.fast_map, &cs->fast_map, sizeof (cs->fast_map)); - DUMP_FIELD_COPY (&out, cs, code_offset); + if (cs_i < charset_table_used) /* Don't look at uninitialized data. */ + { + DUMP_FIELD_COPY (&out, cs, id); + dump_field_lv (ctx, &out, cs, &cs->attributes, WEIGHT_NORMAL); + DUMP_FIELD_COPY (&out, cs, dimension); + memcpy (out.code_space, &cs->code_space, sizeof (cs->code_space)); + if (cs->code_space_mask) + dump_field_fixup_later (ctx, &out, cs, &cs->code_space_mask); + DUMP_FIELD_COPY (&out, cs, code_linear_p); + DUMP_FIELD_COPY (&out, cs, iso_chars_96); + DUMP_FIELD_COPY (&out, cs, ascii_compatible_p); + DUMP_FIELD_COPY (&out, cs, supplementary_p); + DUMP_FIELD_COPY (&out, cs, compact_codes_p); + DUMP_FIELD_COPY (&out, cs, unified_p); + DUMP_FIELD_COPY (&out, cs, iso_final); + DUMP_FIELD_COPY (&out, cs, iso_revision); + DUMP_FIELD_COPY (&out, cs, emacs_mule_id); + DUMP_FIELD_COPY (&out, cs, method); + DUMP_FIELD_COPY (&out, cs, min_code); + DUMP_FIELD_COPY (&out, cs, max_code); + DUMP_FIELD_COPY (&out, cs, char_index_offset); + DUMP_FIELD_COPY (&out, cs, min_char); + DUMP_FIELD_COPY (&out, cs, max_char); + DUMP_FIELD_COPY (&out, cs, invalid_code); + memcpy (out.fast_map, &cs->fast_map, sizeof (cs->fast_map)); + DUMP_FIELD_COPY (&out, cs, code_offset); + } dump_off offset = dump_object_finish (ctx, &out, sizeof (out)); if (cs_i < charset_table_used && cs->code_space_mask) dump_remember_cold_op (ctx, COLD_OP_CHARSET, @@ -3249,14 +3306,17 @@ dump_charset_table (struct dump_context *ctx) { struct dump_flags old_flags = ctx->flags; ctx->flags.pack_objects = true; - dump_align_output (ctx, DUMP_ALIGNMENT); + dump_align_output (ctx, alignof (struct charset)); dump_off offset = ctx->offset; + if (dump_set_referrer (ctx)) + ctx->current_referrer = build_string ("charset_table"); /* We are dumping the entire table, not just the used slots, because otherwise when we restore from the pdump file, the actual size of the table will be smaller than charset_table_size, and we will crash if/when a new charset is defined. */ for (int i = 0; i < charset_table_size; ++i) dump_charset (ctx, i); + dump_clear_referrer (ctx); dump_emacs_reloc_to_dump_ptr_raw (ctx, &charset_table, offset); ctx->flags = old_flags; return offset; @@ -3308,7 +3368,7 @@ dump_sort_copied_objects (struct dump_context *ctx) file and the copy into Emacs in-order, where prefetch will be most effective. */ ctx->copied_queue = - Fsort (Fnreverse (ctx->copied_queue), + CALLN (Fsort, Fnreverse (ctx->copied_queue), Qdump_emacs_portable__sort_predicate_copied); } @@ -3875,7 +3935,7 @@ drain_reloc_list (struct dump_context *ctx, { struct dump_flags old_flags = ctx->flags; ctx->flags.pack_objects = true; - Lisp_Object relocs = Fsort (Fnreverse (*reloc_list), + Lisp_Object relocs = CALLN (Fsort, Fnreverse (*reloc_list), Qdump_emacs_portable__sort_predicate); *reloc_list = Qnil; dump_align_output (ctx, max (alignof (struct dump_reloc), @@ -3997,7 +4057,7 @@ static void dump_do_fixups (struct dump_context *ctx) { dump_off saved_offset = ctx->offset; - Lisp_Object fixups = Fsort (Fnreverse (ctx->fixups), + Lisp_Object fixups = CALLN (Fsort, Fnreverse (ctx->fixups), Qdump_emacs_portable__sort_predicate); Lisp_Object prev_fixup = Qnil; ctx->fixups = Qnil; @@ -4212,22 +4272,19 @@ types. */) dump_drain_deferred_symbols (ctx); dump_drain_normal_queue (ctx); } - while (!dump_queue_empty_p (&ctx->dump_queue) - || !NILP (ctx->deferred_hash_tables) - || !NILP (ctx->deferred_symbols)); + while (!(dump_queue_empty_p (&ctx->dump_queue) + && NILP (ctx->deferred_hash_tables) + && NILP (ctx->deferred_symbols))); ctx->header.hash_list = ctx->offset; dump_hash_table_list (ctx); - do - { - dump_drain_deferred_hash_tables (ctx); - dump_drain_deferred_symbols (ctx); - dump_drain_normal_queue (ctx); - } - while (!dump_queue_empty_p (&ctx->dump_queue) - || !NILP (ctx->deferred_hash_tables) - || !NILP (ctx->deferred_symbols)); + /* dump_hash_table_list just adds a new vector to the dump but all + its content should already have been in the dump, so it doesn't + add anything to any queue. */ + eassert (dump_queue_empty_p (&ctx->dump_queue) + && NILP (ctx->deferred_hash_tables) + && NILP (ctx->deferred_symbols)); dump_sort_copied_objects (ctx); @@ -5584,10 +5641,7 @@ pdumper_load (const char *dump_filename, char *argv0) struct dump_header header_buf = { 0 }; struct dump_header *header = &header_buf; - struct dump_memory_map sections[NUMBER_DUMP_SECTIONS]; - - /* Use memset instead of "= { 0 }" to work around GCC bug 105961. */ - memset (sections, 0, sizeof sections); + struct dump_memory_map sections[NUMBER_DUMP_SECTIONS] = { 0 }; const struct timespec start_time = current_timespec (); char *dump_filename_copy; |