object_ct total_floats, total_free_floats;
object_ct total_intervals, total_free_intervals;
object_ct total_buffers;
+
+ /* Size of the ancillary arrays of live hash-table objects.
+ The objects themselves are not included (counted as vectors above). */
+ byte_ct total_hash_table_bytes;
} gcstat;
+/* Total size of ancillary arrays of all allocated hash-table objects,
+ both dead and alive. This number is always kept up-to-date. */
+static ptrdiff_t hash_table_allocated_bytes = 0;
+
/* Points to memory space allocated as "spare", to be freed if we run
out of memory. We keep one large block, four cons-blocks, and
two string blocks. */
}
#endif
break;
+ case PVEC_HASH_TABLE:
+ {
+ struct Lisp_Hash_Table *h = PSEUDOVEC_STRUCT (vector, Lisp_Hash_Table);
+ if (h->table_size > 0)
+ {
+ eassert (h->index_size > 1);
+ xfree (h->index);
+ xfree (h->key_and_value);
+ xfree (h->next);
+ xfree (h->hash);
+ ptrdiff_t bytes = (h->table_size * (2 * sizeof *h->key_and_value
+ + sizeof *h->hash
+ + sizeof *h->next)
+ + h->index_size * sizeof *h->index);
+ hash_table_allocated_bytes -= bytes;
+ }
+ }
/* Keep the switch exhaustive. */
case PVEC_NORMAL_VECTOR:
case PVEC_FREE:
case PVEC_WINDOW:
case PVEC_BOOL_VECTOR:
case PVEC_BUFFER:
- case PVEC_HASH_TABLE:
case PVEC_TERMINAL:
case PVEC_WINDOW_CONFIGURATION:
case PVEC_OTHER:
lisp_free (lv);
}
}
+
+ gcstat.total_hash_table_bytes = hash_table_allocated_bytes;
}
/* Maximum number of elements in a vector. This is a macro so that it
return 0;
}
+/* Like xmalloc, but makes allocation count toward the total consing.
+ Return NULL for a zero-sized allocation. */
+void *
+hash_table_alloc_bytes (ptrdiff_t nbytes)
+{
+ if (nbytes == 0)
+ return NULL;
+ tally_consing (nbytes);
+ hash_table_allocated_bytes += nbytes;
+ return xmalloc (nbytes);
+}
+
+/* Like xfree, but makes allocation count toward the total consing. */
+void
+hash_table_free_bytes (void *p, ptrdiff_t nbytes)
+{
+ tally_consing (-nbytes);
+ hash_table_allocated_bytes -= nbytes;
+ xfree (p);
+}
+
+
/***********************************************************************
Pure Storage Management
***********************************************************************/
pure->test.name = purecopy (table->test.name);
pure->test.user_hash_function = purecopy (table->test.user_hash_function);
pure->test.user_cmp_function = purecopy (table->test.user_cmp_function);
- pure->hash = purecopy (table->hash);
- pure->next = purecopy (table->next);
- pure->index = purecopy (table->index);
- pure->key_and_value = purecopy (table->key_and_value);
+
+ if (table->table_size > 0)
+ {
+ ptrdiff_t hash_bytes = table->table_size * sizeof *table->hash;
+ pure->hash = pure_alloc (hash_bytes, -(int)sizeof *table->hash);
+ memcpy (pure->hash, table->hash, hash_bytes);
+
+ ptrdiff_t next_bytes = table->table_size * sizeof *table->next;
+ pure->next = pure_alloc (next_bytes, -(int)sizeof *table->next);
+ memcpy (pure->next, table->next, next_bytes);
+
+ ptrdiff_t nvalues = table->table_size * 2;
+ ptrdiff_t kv_bytes = nvalues * sizeof *table->key_and_value;
+ pure->key_and_value = pure_alloc (kv_bytes,
+ -(int)sizeof *table->key_and_value);
+ for (ptrdiff_t i = 0; i < nvalues; i++)
+ pure->key_and_value[i] = purecopy (table->key_and_value[i]);
+
+ ptrdiff_t index_bytes = table->index_size * sizeof *table->index;
+ pure->index = pure_alloc (index_bytes, -(int)sizeof *table->index);
+ memcpy (pure->index, table->index, index_bytes);
+ }
return pure;
}
tot += object_bytes (gcstat.total_floats, sizeof (struct Lisp_Float));
tot += object_bytes (gcstat.total_intervals, sizeof (struct interval));
tot += object_bytes (gcstat.total_strings, sizeof (struct Lisp_String));
+ tot += gcstat.total_hash_table_bytes;
return tot;
}
case PVEC_HASH_TABLE:
{
struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *)ptr;
- ptrdiff_t size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK;
set_vector_marked (ptr);
- mark_stack_push_values (ptr->contents, size);
mark_stack_push_value (h->test.name);
mark_stack_push_value (h->test.user_hash_function);
mark_stack_push_value (h->test.user_cmp_function);
if (h->weakness == Weak_None)
- mark_stack_push_value (h->key_and_value);
+ mark_stack_push_values (h->key_and_value,
+ 2 * h->table_size);
else
{
- /* For weak tables, mark only the vector and not its
+ /* For weak tables, don't mark the
contents --- that's what makes it weak. */
eassert (h->next_weak == NULL);
h->next_weak = weak_hash_tables;
weak_hash_tables = h;
- if (!PURE_P (h->key_and_value))
- set_vector_marked (XVECTOR (h->key_and_value));
}
break;
}
static void
set_hash_next_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val)
{
- gc_aset (h->next, idx, make_fixnum (val));
+ eassert (idx >= 0 && idx < h->table_size);
+ h->next[idx] = val;
}
static void
set_hash_hash_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, Lisp_Object val)
{
- gc_aset (h->hash, idx, val);
+ eassert (idx >= 0 && idx < h->table_size);
+ h->hash[idx] = val;
}
static void
set_hash_index_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val)
{
- gc_aset (h->index, idx, make_fixnum (val));
+ eassert (idx >= 0 && idx < h->index_size);
+ h->index[idx] = val;
}
/* If OBJ is a Lisp hash table, return a pointer to its struct
static ptrdiff_t
HASH_NEXT (struct Lisp_Hash_Table *h, ptrdiff_t idx)
{
- return XFIXNUM (AREF (h->next, idx));
+ eassert (idx >= 0 && idx < h->table_size);
+ return h->next[idx];
}
/* Return the index of the element in hash table H that is the start
static ptrdiff_t
HASH_INDEX (struct Lisp_Hash_Table *h, ptrdiff_t idx)
{
- return XFIXNUM (AREF (h->index, idx));
+ eassert (idx >= 0 && idx < h->index_size);
+ return h->index[idx];
}
/* Restore a hash table's mutability after the critical section exits. */
static struct Lisp_Hash_Table *
allocate_hash_table (void)
{
- return ALLOCATE_PSEUDOVECTOR (struct Lisp_Hash_Table,
- index, PVEC_HASH_TABLE);
+ return ALLOCATE_PLAIN_PSEUDOVECTOR (struct Lisp_Hash_Table, PVEC_HASH_TABLE);
}
/* An upper bound on the size of a hash table index. It must fit in
return index_size;
}
+/* Constant hash index vector used when the table size is zero.
+ This avoids allocating it from the heap. */
+static const ptrdiff_t empty_hash_index_vector[] = {-1};
+
/* Create and initialize a new hash table.
TEST specifies the test the hash table will use to compare keys.
make_hash_table (struct hash_table_test test, EMACS_INT size,
hash_table_weakness_t weak, bool purecopy)
{
- struct Lisp_Hash_Table *h;
- Lisp_Object table;
- ptrdiff_t i;
-
- /* Preconditions. */
eassert (SYMBOLP (test.name));
- eassert (0 <= size && size <= MOST_POSITIVE_FIXNUM);
+ eassert (0 <= size && size <= min (MOST_POSITIVE_FIXNUM, PTRDIFF_MAX));
- /* Allocate a table and initialize it. */
- h = allocate_hash_table ();
+ struct Lisp_Hash_Table *h = allocate_hash_table ();
- /* Initialize hash table slots. */
h->test = test;
h->weakness = weak;
h->count = 0;
- h->key_and_value = make_vector (2 * size, HASH_UNUSED_ENTRY_KEY);
- h->hash = make_nil_vector (size);
- h->next = make_vector (size, make_fixnum (-1));
- h->index = make_vector (hash_index_size (size), make_fixnum (-1));
+ h->table_size = size;
+ int index_size = hash_index_size (size);
+ h->index_size = index_size;
+
+ if (size == 0)
+ {
+ h->key_and_value = NULL;
+ h->hash = NULL;
+ h->next = NULL;
+ eassert (index_size == 1);
+ h->index = (ptrdiff_t *)empty_hash_index_vector;
+ h->next_free = -1;
+ }
+ else
+ {
+ h->key_and_value = hash_table_alloc_bytes (2 * size
+ * sizeof *h->key_and_value);
+ for (ptrdiff_t i = 0; i < 2 * size; i++)
+ h->key_and_value[i] = HASH_UNUSED_ENTRY_KEY;
+
+ h->hash = hash_table_alloc_bytes (size * sizeof *h->hash);
+ memclear (h->hash, size * sizeof *h->hash);
+
+ h->next = hash_table_alloc_bytes (size * sizeof *h->next);
+ for (ptrdiff_t i = 0; i < size - 1; i++)
+ h->next[i] = i + 1;
+ h->next[size - 1] = -1;
+
+ h->index = hash_table_alloc_bytes (index_size * sizeof *h->index);
+ for (ptrdiff_t i = 0; i < index_size; i++)
+ h->index[i] = -1;
+
+ h->next_free = 0;
+ }
+
h->next_weak = NULL;
h->purecopy = purecopy;
h->mutable = true;
- /* Set up the free list. */
- for (i = 0; i < size - 1; ++i)
- set_hash_next_slot (h, i, i + 1);
- if (size > 0)
- set_hash_next_slot (h, size - 1, -1);
- h->next_free = size > 0 ? 0 : -1;
-
+ Lisp_Object table;
XSET_HASH_TABLE (table, h);
eassert (HASH_TABLE_P (table));
eassert (XHASH_TABLE (table) == h);
h2 = allocate_hash_table ();
*h2 = *h1;
h2->mutable = true;
- h2->key_and_value = Fcopy_sequence (h1->key_and_value);
- h2->hash = Fcopy_sequence (h1->hash);
- h2->next = Fcopy_sequence (h1->next);
- h2->index = Fcopy_sequence (h1->index);
+
+ if (h1->table_size > 0)
+ {
+ ptrdiff_t kv_bytes = 2 * h1->table_size * sizeof *h1->key_and_value;
+ h2->key_and_value = hash_table_alloc_bytes (kv_bytes);
+ memcpy (h2->key_and_value, h1->key_and_value, kv_bytes);
+
+ ptrdiff_t hash_bytes = h1->table_size * sizeof *h1->hash;
+ h2->hash = hash_table_alloc_bytes (hash_bytes);
+ memcpy (h2->hash, h1->hash, hash_bytes);
+
+ ptrdiff_t next_bytes = h1->table_size * sizeof *h1->next;
+ h2->next = hash_table_alloc_bytes (next_bytes);
+ memcpy (h2->next, h1->next, next_bytes);
+
+ ptrdiff_t index_bytes = h1->index_size * sizeof *h1->index;
+ h2->index = hash_table_alloc_bytes (index_bytes);
+ memcpy (h2->index, h1->index, index_bytes);
+ }
XSET_HASH_TABLE (table, h2);
return table;
}
-/* Allocate a Lisp vector of NEW_SIZE elements.
- Copy elements from VEC and leave the rest undefined. */
-static Lisp_Object
-alloc_larger_vector (Lisp_Object vec, ptrdiff_t new_size)
-{
- eassert (VECTORP (vec));
- ptrdiff_t old_size = ASIZE (vec);
- eassert (new_size >= old_size);
- struct Lisp_Vector *v = allocate_vector (new_size);
- memcpy (v->contents, XVECTOR (vec)->contents, old_size * sizeof *v->contents);
- XSETVECTOR (vec, v);
- return vec;
-}
-
/* Compute index into the index vector from a hash value. */
static inline ptrdiff_t
hash_index_index (struct Lisp_Hash_Table *h, Lisp_Object hash_code)
{
- return XUFIXNUM (hash_code) % ASIZE (h->index);
+ eassert (h->index_size > 0);
+ return XUFIXNUM (hash_code) % h->index_size;
}
/* Resize hash table H if it's too full. If H cannot be resized
/* Allocate all the new vectors before updating *H, to
avoid problems if memory is exhausted. */
- Lisp_Object next = alloc_larger_vector (h->next, new_size);
+ ptrdiff_t *next = hash_table_alloc_bytes (new_size * sizeof *next);
for (ptrdiff_t i = old_size; i < new_size - 1; i++)
- ASET (next, i, make_fixnum (i + 1));
- ASET (next, new_size - 1, make_fixnum (-1));
+ next[i] = i + 1;
+ next[new_size - 1] = -1;
- /* Build the new&larger key_and_value vector, making sure the new
- fields are initialized to `unbound`. */
- Lisp_Object key_and_value
- = alloc_larger_vector (h->key_and_value, 2 * new_size);
+ Lisp_Object *key_and_value
+ = hash_table_alloc_bytes (2 * new_size * sizeof *key_and_value);
+ memcpy (key_and_value, h->key_and_value,
+ 2 * old_size * sizeof *key_and_value);
for (ptrdiff_t i = 2 * old_size; i < 2 * new_size; i++)
- ASET (key_and_value, i, HASH_UNUSED_ENTRY_KEY);
+ key_and_value[i] = HASH_UNUSED_ENTRY_KEY;
- Lisp_Object hash = alloc_larger_vector (h->hash, new_size);
- memclear (XVECTOR (hash)->contents + old_size,
- (new_size - old_size) * word_size);
+ Lisp_Object *hash = hash_table_alloc_bytes (new_size * sizeof *hash);
+ memcpy (hash, h->hash, old_size * sizeof *hash);
+ memclear (hash + old_size, (new_size - old_size) * word_size);
+
+ ptrdiff_t old_index_size = h->index_size;
ptrdiff_t index_size = hash_index_size (new_size);
- h->index = make_vector (index_size, make_fixnum (-1));
+ ptrdiff_t *index = hash_table_alloc_bytes (index_size * sizeof *index);
+ for (ptrdiff_t i = 0; i < index_size; i++)
+ index[i] = -1;
+
+ h->index_size = index_size;
+ h->table_size = new_size;
+ h->next_free = old_size;
+
+ if (old_index_size > 1)
+ hash_table_free_bytes (h->index, old_index_size * sizeof *h->index);
+ h->index = index;
+
+ hash_table_free_bytes (h->key_and_value,
+ 2 * old_size * sizeof *h->key_and_value);
h->key_and_value = key_and_value;
+
+ hash_table_free_bytes (h->hash, old_size * sizeof *h->hash);
h->hash = hash;
+
+ hash_table_free_bytes (h->next, old_size * sizeof *h->next);
h->next = next;
- h->next_free = old_size;
- /* Rehash. */
+ h->key_and_value = key_and_value;
+
+ /* Rehash: all data occupy entries 0..old_size-1. */
for (ptrdiff_t i = 0; i < old_size; i++)
- if (!NILP (HASH_HASH (h, i)))
- {
- Lisp_Object hash_code = HASH_HASH (h, i);
- ptrdiff_t start_of_bucket = hash_index_index (h, hash_code);
- set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
- set_hash_index_slot (h, start_of_bucket, i);
- }
+ {
+ Lisp_Object hash_code = HASH_HASH (h, i);
+ ptrdiff_t start_of_bucket = hash_index_index (h, hash_code);
+ set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
+ set_hash_index_slot (h, start_of_bucket, i);
+ }
#ifdef ENABLE_CHECKING
if (HASH_TABLE_P (Vpurify_flag) && XHASH_TABLE (Vpurify_flag) == h)
/* Freezing discarded most non-essential information; recompute it.
The allocation is minimal with no room for growth. */
h->test = *hash_table_test_from_std (h->frozen_test);
- ptrdiff_t size = ASIZE (h->key_and_value) / 2;
- h->count = size;
+ ptrdiff_t size = h->count;
+ h->table_size = size;
ptrdiff_t index_size = hash_index_size (size);
+ h->index_size = index_size;
h->next_free = -1;
- h->hash = make_nil_vector (size);
- h->next = make_vector (size, make_fixnum (-1));
- h->index = make_vector (index_size, make_fixnum (-1));
+ h->hash = hash_table_alloc_bytes (size * sizeof *h->hash);
+ memclear (h->hash, size * sizeof *h->hash);
+
+ h->next = hash_table_alloc_bytes (size * sizeof *h->next);
+ for (ptrdiff_t i = 0; i < size; i++)
+ h->next[i] = -1;
+
+ h->index = hash_table_alloc_bytes (index_size * sizeof *h->index);
+ for (ptrdiff_t i = 0; i < index_size; i++)
+ h->index[i] = -1;
/* Recompute the actual hash codes for each entry in the table.
Order is still invalid. */
if (h->count > 0)
{
ptrdiff_t size = HASH_TABLE_SIZE (h);
- memclear (xvector_contents (h->hash), size * word_size);
+ memclear (h->hash, size * word_size);
for (ptrdiff_t i = 0; i < size; i++)
{
set_hash_next_slot (h, i, i < size - 1 ? i + 1 : -1);
set_hash_value_slot (h, i, Qnil);
}
- for (ptrdiff_t i = 0; i < ASIZE (h->index); i++)
- ASET (h->index, i, make_fixnum (-1));
+ for (ptrdiff_t i = 0; i < h->index_size; i++)
+ h->index[i] = -1;
h->next_free = 0;
h->count = 0;
bool
sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p)
{
- ptrdiff_t n = gc_asize (h->index);
+ ptrdiff_t n = h->index_size;
bool marked = false;
for (ptrdiff_t bucket = 0; bucket < n; ++bucket)
/* Clear key, value, and hash. */
set_hash_key_slot (h, i, HASH_UNUSED_ENTRY_KEY);
set_hash_value_slot (h, i, Qnil);
- if (!NILP (h->hash))
- set_hash_hash_slot (h, i, Qnil);
+ set_hash_hash_slot (h, i, Qnil);
eassert (h->count != 0);
h->count--;
struct Lisp_Hash_Table *h = check_hash_table (hash_table);
ptrdiff_t size = HASH_TABLE_SIZE (h);
ptrdiff_t *freq = xzalloc (size * sizeof *freq);
- ptrdiff_t index_size = ASIZE (h->index);
+ ptrdiff_t index_size = h->index_size;
for (ptrdiff_t i = 0; i < index_size; i++)
{
ptrdiff_t n = 0;
{
struct Lisp_Hash_Table *h = check_hash_table (hash_table);
Lisp_Object ret = Qnil;
- ptrdiff_t index_size = ASIZE (h->index);
+ ptrdiff_t index_size = h->index_size;
for (ptrdiff_t i = 0; i < index_size; i++)
{
Lisp_Object bucket = Qnil;
(Lisp_Object hash_table)
{
struct Lisp_Hash_Table *h = check_hash_table (hash_table);
- ptrdiff_t index_size = ASIZE (h->index);
- return make_int (index_size);
+ return make_int (h->index_size);
}
\f
The table is physically split into three vectors (hash, next,
key_and_value) which may or may not be beneficial. */
- /* Vector of hash codes, or nil if the table needs rehashing.
- If the I-th entry is unused, then hash[I] should be nil. */
- Lisp_Object hash;
+ /* Bucket vector. An entry of -1 indicates no item is present,
+ and a nonnegative entry is the index of the first item in
+ a collision chain.
+ This vector is index_size entries long.
+ If index_size is 1 (and table_size is 0), then this is the
+ constant read-only vector {-1}, shared between all instances.
+ Otherwise it is heap-allocated. */
+ ptrdiff_t *index;
+ ptrdiff_t index_size; /* Size of the index vector. */
+
+ ptrdiff_t table_size; /* Size of the next and hash vectors. */
+
+ /* Vector of hash codes. Each entry is either a fixnum, or nil if unused.
+ This vector is table_size entries long. */
+ Lisp_Object *hash;
/* Vector used to chain entries. If entry I is free, next[I] is the
entry number of the next free item. If entry I is non-free,
next[I] is the index of the next entry in the collision chain,
- or -1 if there is such entry. */
- Lisp_Object next;
-
- /* Bucket vector. An entry of -1 indicates no item is present,
- and a nonnegative entry is the index of the first item in
- a collision chain. This vector's size can be larger than the
- hash table size to reduce collisions. */
- Lisp_Object index;
-
- /* Only the fields above are traced normally by the GC. The ones after
- 'index' are special and are either ignored by the GC or traced in
- a special way (e.g. because of weakness). */
+ or -1 if there is no such entry.
+ This vector is table_size entries long. */
+ ptrdiff_t *next;
/* Number of key/value entries in the table. */
ptrdiff_t count;
/* Vector of keys and values. The key of item I is found at index
2 * I, the value is found at index 2 * I + 1.
If the key is HASH_UNUSED_ENTRY_KEY, then this slot is unused.
- This is gc_marked specially if the table is weak. */
- Lisp_Object key_and_value;
+ This is gc_marked specially if the table is weak.
+ This vector is 2 * table_size entries long. */
+ Lisp_Object *key_and_value;
/* The comparison and hash functions. */
struct hash_table_test test;
struct Lisp_Hash_Table *next_weak;
} GCALIGNED_STRUCT;
-/* Sanity-check pseudovector layout. */
-verify (offsetof (struct Lisp_Hash_Table, hash) == header_size);
-
/* Key value that marks an unused hash table entry. */
#define HASH_UNUSED_ENTRY_KEY Qunbound
INLINE Lisp_Object
HASH_KEY (const struct Lisp_Hash_Table *h, ptrdiff_t idx)
{
- return AREF (h->key_and_value, 2 * idx);
+ eassert (idx >= 0 && idx < h->table_size);
+ return h->key_and_value[2 * idx];
}
/* Value is the value part of entry IDX in hash table H. */
INLINE Lisp_Object
HASH_VALUE (const struct Lisp_Hash_Table *h, ptrdiff_t idx)
{
- return AREF (h->key_and_value, 2 * idx + 1);
+ eassert (idx >= 0 && idx < h->table_size);
+ return h->key_and_value[2 * idx + 1];
}
/* Value is the hash code computed for entry IDX in hash table H. */
INLINE Lisp_Object
HASH_HASH (const struct Lisp_Hash_Table *h, ptrdiff_t idx)
{
- return AREF (h->hash, idx);
+ eassert (idx >= 0 && idx < h->table_size);
+ return h->hash[idx];
}
/* Value is the size of hash table H. */
INLINE ptrdiff_t
HASH_TABLE_SIZE (const struct Lisp_Hash_Table *h)
{
- return ASIZE (h->next);
+ return h->table_size;
}
/* Compute hash value for KEY in hash table H. */
INLINE void
set_hash_key_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, Lisp_Object val)
{
- gc_aset (h->key_and_value, 2 * idx, val);
+ eassert (idx >= 0 && idx < h->table_size);
+ h->key_and_value[2 * idx] = val;
}
INLINE void
set_hash_value_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, Lisp_Object val)
{
- gc_aset (h->key_and_value, 2 * idx + 1, val);
+ eassert (idx >= 0 && idx < h->table_size);
+ h->key_and_value[2 * idx + 1] = val;;
}
/* Use these functions to set Lisp_Object
extern struct buffer *allocate_buffer (void) ATTRIBUTE_RETURNS_NONNULL;
extern int valid_lisp_object_p (Lisp_Object);
+void *hash_table_alloc_bytes (ptrdiff_t nbytes);
+void hash_table_free_bytes (void *p, ptrdiff_t nbytes);
+
/* Defined in gmalloc.c. */
#if !defined DOUG_LEA_MALLOC && !defined HYBRID_MALLOC && !defined SYSTEM_MALLOC
extern size_t __malloc_extra_blocks;
/* Return a vector of KEY, VALUE pairs in the given hash table H.
No room for growth is included. */
-static Lisp_Object
+static Lisp_Object *
hash_table_contents (struct Lisp_Hash_Table *h)
{
ptrdiff_t old_size = HASH_TABLE_SIZE (h);
ptrdiff_t size = h->count;
- Lisp_Object key_and_value = make_uninit_vector (2 * size);
+ 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
for (ptrdiff_t i = 0; i < old_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));
+ key_and_value[n++] = HASH_KEY (h, i);
+ key_and_value[n++] = HASH_VALUE (h, i);
}
return key_and_value;
hash_table_freeze (struct Lisp_Hash_Table *h)
{
h->key_and_value = hash_table_contents (h);
- eassert (ASIZE (h->key_and_value) == h->count * 2);
- h->next = Qnil;
- h->hash = Qnil;
- h->index = Qnil;
- h->count = 0;
+ h->next = NULL;
+ h->hash = NULL;
+ h->index = NULL;
+ h->table_size = 0;
+ h->index_size = 0;
h->frozen_test = hash_table_std_test (&h->test);
}
+static dump_off
+dump_hash_table_contents (struct dump_context *ctx, struct Lisp_Hash_Table *h)
+{
+ dump_align_output (ctx, DUMP_ALIGNMENT);
+ dump_off start_offset = ctx->offset;
+ ptrdiff_t n = 2 * h->count;
+
+ 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)
{
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, weakness);
DUMP_FIELD_COPY (out, hash, purecopy);
DUMP_FIELD_COPY (out, hash, mutable);
DUMP_FIELD_COPY (out, hash, frozen_test);
- dump_field_lv (ctx, out, hash, &hash->key_and_value, WEIGHT_STRONG);
+ 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
if (HASH_TABLE_P (obj))
{
struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
- obj = h->key_and_value;
- continue;
+ pp_stack_push_values (h->key_and_value,
+ 2 * h->table_size);
}
break;
}