summaryrefslogtreecommitdiff
path: root/src/pdumper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdumper.c')
-rw-r--r--src/pdumper.c300
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;