summaryrefslogtreecommitdiff
path: root/src/alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c168
1 files changed, 101 insertions, 67 deletions
diff --git a/src/alloc.c b/src/alloc.c
index f57e22d9cc0..b35f7c4333f 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -1280,28 +1280,32 @@ mark_interval (register INTERVAL i, Lisp_Object dummy)
#define LARGE_STRING_BYTES 1024
-/* Struct or union describing string memory sub-allocated from an sblock.
- This is where the contents of Lisp strings are stored. */
+/* The SDATA typedef is a struct or union describing string memory
+ sub-allocated from an sblock. This is where the contents of Lisp
+ strings are stored. */
-#ifdef GC_CHECK_STRING_BYTES
-
-typedef struct
+struct sdata
{
/* Back-pointer to the string this sdata belongs to. If null, this
- structure is free, and the NBYTES member of the union below
+ structure is free, and NBYTES (in this structure or in the union below)
contains the string's byte size (the same value that STRING_BYTES
would return if STRING were non-null). If non-null, STRING_BYTES
(STRING) is the size of the data, and DATA contains the string's
contents. */
struct Lisp_String *string;
+#ifdef GC_CHECK_STRING_BYTES
ptrdiff_t nbytes;
+#endif
+
unsigned char data[FLEXIBLE_ARRAY_MEMBER];
-} sdata;
+};
+
+#ifdef GC_CHECK_STRING_BYTES
+typedef struct sdata sdata;
#define SDATA_NBYTES(S) (S)->nbytes
#define SDATA_DATA(S) (S)->data
-#define SDATA_SELECTOR(member) member
#else
@@ -1309,12 +1313,16 @@ typedef union
{
struct Lisp_String *string;
- /* When STRING is non-null. */
- struct
- {
- struct Lisp_String *string;
- unsigned char data[FLEXIBLE_ARRAY_MEMBER];
- } u;
+ /* When STRING is nonnull, this union is actually of type 'struct sdata',
+ which has a flexible array member. However, if implemented by
+ giving this union a member of type 'struct sdata', the union
+ could not be the last (flexible) member of 'struct sblock',
+ because C99 prohibits a flexible array member from having a type
+ that is itself a flexible array. So, comment this member out here,
+ but remember that the option's there when using this union. */
+#if 0
+ struct sdata u;
+#endif
/* When STRING is null. */
struct
@@ -1325,13 +1333,11 @@ typedef union
} sdata;
#define SDATA_NBYTES(S) (S)->n.nbytes
-#define SDATA_DATA(S) (S)->u.data
-#define SDATA_SELECTOR(member) u.member
+#define SDATA_DATA(S) ((struct sdata *) (S))->data
#endif /* not GC_CHECK_STRING_BYTES */
-#define SDATA_DATA_OFFSET offsetof (sdata, SDATA_SELECTOR (data))
-
+enum { SDATA_DATA_OFFSET = offsetof (struct sdata, data) };
/* Structure describing a block of memory which is sub-allocated to
obtain string data memory for strings. Blocks for small strings
@@ -1347,8 +1353,8 @@ struct sblock
of the sblock if there isn't any space left in this block. */
sdata *next_free;
- /* Start of data. */
- sdata first_data;
+ /* String data. */
+ sdata data[FLEXIBLE_ARRAY_MEMBER];
};
/* Number of Lisp strings in a string_block structure. The 1020 is
@@ -1464,7 +1470,7 @@ static ptrdiff_t const STRING_BYTES_MAX =
min (STRING_BYTES_BOUND,
((SIZE_MAX - XMALLOC_OVERRUN_CHECK_OVERHEAD
- GC_STRING_EXTRA
- - offsetof (struct sblock, first_data)
+ - offsetof (struct sblock, data)
- SDATA_DATA_OFFSET)
& ~(sizeof (EMACS_INT) - 1)));
@@ -1507,7 +1513,7 @@ check_sblock (struct sblock *b)
end = b->next_free;
- for (from = &b->first_data; from < end; from = from_end)
+ for (from = b->data; from < end; from = from_end)
{
/* Compute the next FROM here because copying below may
overwrite data we need to compute it. */
@@ -1535,7 +1541,7 @@ check_string_bytes (bool all_p)
for (b = large_sblocks; b; b = b->next)
{
- struct Lisp_String *s = b->first_data.string;
+ struct Lisp_String *s = b->data[0].string;
if (s)
string_bytes (s);
}
@@ -1669,7 +1675,7 @@ allocate_string_data (struct Lisp_String *s,
if (nbytes > LARGE_STRING_BYTES)
{
- size_t size = offsetof (struct sblock, first_data) + needed;
+ size_t size = offsetof (struct sblock, data) + needed;
#ifdef DOUG_LEA_MALLOC
/* Prevent mmap'ing the chunk. Lisp data may not be mmap'ed
@@ -1691,8 +1697,8 @@ allocate_string_data (struct Lisp_String *s,
mallopt (M_MMAP_MAX, MMAP_MAX_AREAS);
#endif
- b->next_free = &b->first_data;
- b->first_data.string = NULL;
+ b->next_free = b->data;
+ b->data[0].string = NULL;
b->next = large_sblocks;
large_sblocks = b;
}
@@ -1703,8 +1709,8 @@ allocate_string_data (struct Lisp_String *s,
{
/* Not enough room in the current sblock. */
b = lisp_malloc (SBLOCK_SIZE, MEM_TYPE_NON_LISP);
- b->next_free = &b->first_data;
- b->first_data.string = NULL;
+ b->next_free = b->data;
+ b->data[0].string = NULL;
b->next = NULL;
if (current_sblock)
@@ -1858,7 +1864,7 @@ free_large_strings (void)
{
next = b->next;
- if (b->first_data.string == NULL)
+ if (b->data[0].string == NULL)
lisp_free (b);
else
{
@@ -1885,7 +1891,7 @@ compact_small_strings (void)
to, and TB_END is the end of TB. */
tb = oldest_sblock;
tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE);
- to = &tb->first_data;
+ to = tb->data;
/* Step through the blocks from the oldest to the youngest. We
expect that old blocks will stabilize over time, so that less
@@ -1895,7 +1901,7 @@ compact_small_strings (void)
end = b->next_free;
eassert ((char *) end <= (char *) b + SBLOCK_SIZE);
- for (from = &b->first_data; from < end; from = from_end)
+ for (from = b->data; from < end; from = from_end)
{
/* Compute the next FROM here because copying below may
overwrite data we need to compute it. */
@@ -1932,7 +1938,7 @@ compact_small_strings (void)
tb->next_free = to;
tb = tb->next;
tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE);
- to = &tb->first_data;
+ to = tb->data;
to_end = (sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
}
@@ -2606,16 +2612,35 @@ DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0,
Vector Allocation
***********************************************************************/
+/* Sometimes a vector's contents are merely a pointer internally used
+ in vector allocation code. Usually you don't want to touch this. */
+
+static struct Lisp_Vector *
+next_vector (struct Lisp_Vector *v)
+{
+ return XUNTAG (v->contents[0], 0);
+}
+
+static void
+set_next_vector (struct Lisp_Vector *v, struct Lisp_Vector *p)
+{
+ v->contents[0] = make_lisp_ptr (p, 0);
+}
+
/* This value is balanced well enough to avoid too much internal overhead
for the most common cases; it's not required to be a power of two, but
it's expected to be a mult-of-ROUNDUP_SIZE (see below). */
#define VECTOR_BLOCK_SIZE 4096
-/* Align allocation request sizes to be a multiple of ROUNDUP_SIZE. */
enum
{
- roundup_size = COMMON_MULTIPLE (word_size, USE_LSB_TAG ? GCALIGNMENT : 1)
+ /* Alignment of struct Lisp_Vector objects. */
+ vector_alignment = COMMON_MULTIPLE (ALIGNOF_STRUCT_LISP_VECTOR,
+ USE_LSB_TAG ? GCALIGNMENT : 1),
+
+ /* Vector size requests are a multiple of this. */
+ roundup_size = COMMON_MULTIPLE (vector_alignment, word_size)
};
/* Verify assumptions described above. */
@@ -2663,26 +2688,37 @@ verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS));
eassert ((nbytes) % roundup_size == 0); \
(tmp) = VINDEX (nbytes); \
eassert ((tmp) < VECTOR_MAX_FREE_LIST_INDEX); \
- v->u.next = vector_free_lists[tmp]; \
+ set_next_vector (v, vector_free_lists[tmp]); \
vector_free_lists[tmp] = (v); \
total_free_vector_slots += (nbytes) / word_size; \
} while (0)
/* This internal type is used to maintain the list of large vectors
- which are allocated at their own, e.g. outside of vector blocks. */
+ which are allocated at their own, e.g. outside of vector blocks.
+
+ struct large_vector itself cannot contain a struct Lisp_Vector, as
+ the latter contains a flexible array member and C99 does not allow
+ such structs to be nested. Instead, each struct large_vector
+ object LV is followed by a struct Lisp_Vector, which is at offset
+ large_vector_offset from LV, and whose address is therefore
+ large_vector_vec (&LV). */
struct large_vector
{
- union {
- struct large_vector *vector;
-#if USE_LSB_TAG
- /* We need to maintain ROUNDUP_SIZE alignment for the vector member. */
- unsigned char c[vroundup_ct (sizeof (struct large_vector *))];
-#endif
- } next;
- struct Lisp_Vector v;
+ struct large_vector *next;
};
+enum
+{
+ large_vector_offset = ROUNDUP (sizeof (struct large_vector), vector_alignment)
+};
+
+static struct Lisp_Vector *
+large_vector_vec (struct large_vector *p)
+{
+ return (struct Lisp_Vector *) ((char *) p + large_vector_offset);
+}
+
/* This internal type is used to maintain an underlying storage
for small vectors. */
@@ -2760,7 +2796,7 @@ allocate_vector_from_block (size_t nbytes)
if (vector_free_lists[index])
{
vector = vector_free_lists[index];
- vector_free_lists[index] = vector->u.next;
+ vector_free_lists[index] = next_vector (vector);
total_free_vector_slots -= nbytes / word_size;
return vector;
}
@@ -2774,7 +2810,7 @@ allocate_vector_from_block (size_t nbytes)
{
/* This vector is larger than requested. */
vector = vector_free_lists[index];
- vector_free_lists[index] = vector->u.next;
+ vector_free_lists[index] = next_vector (vector);
total_free_vector_slots -= nbytes / word_size;
/* Excess bytes are used for the smaller vector,
@@ -2933,7 +2969,7 @@ sweep_vectors (void)
for (lv = large_vectors; lv; lv = *lvprev)
{
- vector = &lv->v;
+ vector = large_vector_vec (lv);
if (VECTOR_MARKED_P (vector))
{
VECTOR_UNMARK (vector);
@@ -2949,11 +2985,11 @@ sweep_vectors (void)
else
total_vector_slots
+= header_size / word_size + vector->header.size;
- lvprev = &lv->next.vector;
+ lvprev = &lv->next;
}
else
{
- *lvprev = lv->next.vector;
+ *lvprev = lv->next;
lisp_free (lv);
}
}
@@ -2987,12 +3023,12 @@ allocate_vectorlike (ptrdiff_t len)
else
{
struct large_vector *lv
- = lisp_malloc ((offsetof (struct large_vector, v.u.contents)
+ = lisp_malloc ((large_vector_offset + header_size
+ len * word_size),
MEM_TYPE_VECTORLIKE);
- lv->next.vector = large_vectors;
+ lv->next = large_vectors;
large_vectors = lv;
- p = &lv->v;
+ p = large_vector_vec (lv);
}
#ifdef DOUG_LEA_MALLOC
@@ -3041,7 +3077,7 @@ allocate_pseudovector (int memlen, int lisplen, enum pvec_type tag)
/* Only the first lisplen slots will be traced normally by the GC. */
for (i = 0; i < lisplen; ++i)
- v->u.contents[i] = Qnil;
+ v->contents[i] = Qnil;
XSETPVECTYPESIZE (v, tag, lisplen, memlen - lisplen);
return v;
@@ -3129,7 +3165,7 @@ See also the function `vector'. */)
p = allocate_vector (XFASTINT (length));
sizei = XFASTINT (length);
for (i = 0; i < sizei; i++)
- p->u.contents[i] = init;
+ p->contents[i] = init;
XSETVECTOR (vector, p);
return vector;
@@ -3147,7 +3183,7 @@ usage: (vector &rest OBJECTS) */)
register struct Lisp_Vector *p = XVECTOR (val);
for (i = 0; i < nargs; i++)
- p->u.contents[i] = args[i];
+ p->contents[i] = args[i];
return val;
}
@@ -3156,14 +3192,14 @@ make_byte_code (struct Lisp_Vector *v)
{
/* Don't allow the global zero_vector to become a byte code object. */
eassert(0 < v->header.size);
- if (v->header.size > 1 && STRINGP (v->u.contents[1])
- && STRING_MULTIBYTE (v->u.contents[1]))
+ if (v->header.size > 1 && STRINGP (v->contents[1])
+ && STRING_MULTIBYTE (v->contents[1]))
/* BYTECODE-STRING must have been produced by Emacs 20.2 or the
earlier because they produced a raw 8-bit string for byte-code
and now such a byte-code string is loaded as multibyte while
raw 8-bit characters converted to multibyte form. Thus, now we
must convert them back to the original unibyte form. */
- v->u.contents[1] = Fstring_as_unibyte (v->u.contents[1]);
+ v->contents[1] = Fstring_as_unibyte (v->contents[1]);
XSETPVECTYPE (v, PVEC_COMPILED);
}
@@ -3198,7 +3234,7 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT
to be setcar'd). */
for (i = 0; i < nargs; i++)
- p->u.contents[i] = args[i];
+ p->contents[i] = args[i];
make_byte_code (p);
XSETCOMPILED (val, p);
return val;
@@ -4256,9 +4292,7 @@ live_vector_p (struct mem_node *m, void *p)
vector = ADVANCE (vector, vector_nbytes (vector));
}
}
- else if (m->type == MEM_TYPE_VECTORLIKE
- && (char *) p == ((char *) m->start
- + offsetof (struct large_vector, v)))
+ else if (m->type == MEM_TYPE_VECTORLIKE && p == large_vector_vec (m->start))
/* This memory node corresponds to a large vector. */
return 1;
return 0;
@@ -5189,7 +5223,7 @@ Does not copy symbols. Copies strings without text properties. */)
size &= PSEUDOVECTOR_SIZE_MASK;
vec = XVECTOR (make_pure_vector (size));
for (i = 0; i < size; i++)
- vec->u.contents[i] = Fpurecopy (AREF (obj, i));
+ vec->contents[i] = Fpurecopy (AREF (obj, i));
if (COMPILEDP (obj))
{
XSETPVECTYPE (vec, PVEC_COMPILED);
@@ -5710,7 +5744,7 @@ mark_vectorlike (struct Lisp_Vector *ptr)
The distinction is used e.g. by Lisp_Process which places extra
non-Lisp_Object fields at the end of the structure... */
for (i = 0; i < size; i++) /* ...and then mark its elements. */
- mark_object (ptr->u.contents[i]);
+ mark_object (ptr->contents[i]);
}
/* Like mark_vectorlike but optimized for char-tables (and
@@ -5727,7 +5761,7 @@ mark_char_table (struct Lisp_Vector *ptr)
VECTOR_MARK (ptr);
for (i = 0; i < size; i++)
{
- Lisp_Object val = ptr->u.contents[i];
+ Lisp_Object val = ptr->contents[i];
if (INTEGERP (val) || (SYMBOLP (val) && XSYMBOL (val)->gcmarkbit))
continue;
@@ -5956,10 +5990,10 @@ mark_object (Lisp_Object arg)
VECTOR_MARK (ptr);
for (i = 0; i < size; i++)
if (i != COMPILED_CONSTANTS)
- mark_object (ptr->u.contents[i]);
+ mark_object (ptr->contents[i]);
if (size > COMPILED_CONSTANTS)
{
- obj = ptr->u.contents[COMPILED_CONSTANTS];
+ obj = ptr->contents[COMPILED_CONSTANTS];
goto loop;
}
}