Commit b1573a97 authored by Paul Eggert's avatar Paul Eggert

Use alignas to fix GCALIGN-related bugs

Use alignas and unions to specify alignments of objects needing
addresses that are at least a multiple of GCALIGNMENT.  Using
these standard C facilities should be safer than relying on ad hoc
and poorly-understood features like GCC’s __attribute__
((aligned (N))), the root cause for recent porting bugs like
Bug#29040.  The alignas macro was standardized by C11 and Gnulib
supports alignas for pre-C11 platforms.  I have tested this on Sun
Studio 12 sparc (2007) and GCC 4.4.7 x86-64 (2012) as well as on
more recent platforms like GCC 7.2.1 (2017) on Fedora 26 (both
x86-64 and x86).
* lib-src/make-docfile.c (close_emacs_globals): lispsym is now
just an array of struct Lisp_Symbol, since struct Lisp_Symbol is
now properly aligned.  All uses changed.
* src/alloc.c (NEXT_FREE_LISP_STRING): Just use the new u.next
member; this is simpler and safer than casting a pointer that
might not be aligned properly.
(aligned_Lisp_Symbol): Remove.  No longer needed, now that struct
Lisp_Symbol is aligned properly.  All uses replaced with struct
Lisp_Symbol.
* src/lisp.h (GCALIGNED): Remove, as it does not work as expected:
it can cause the natural alignment to be ignored.  All uses
replaced by unions with a ‘char alignas (GCALIGNMENT)’ member as
described below.
(struct Lisp_Symbol, struct Lisp_Cons, struct Lisp_String):
Change definition from ‘struct TAG { MEMBERS };’ to
‘struct TAG { union { struct { MEMBERS } s; char alignas
(GCALIGNMENT) gcaligned; } u; };’.  This guarantees ‘struct TAG’
to have an alignment that at least max (GCALIGNMENT, N) where N is
its old alignment.  All uses like ‘PTR->MEMBER’ changed to
‘PTR->u.s.MEMBER’; these uses were supposed to be mostly private
anyway.  Verify that the resulting ‘struct TAG’ is properly
aligned for Emacs.
(union vectorlike_header): New member ‘gcaligned’ to guarantee
that this type, and its containing types like ‘struct Lisp_Subr’,
‘struct buffer’ and ‘struct thread_state’, are all properly
aligned for Emacs.
(struct Lisp_String): New union member ‘next’, for the benefit
of NEXT_FREE_LISP_STRING.
(union Aligned_Cons, union Aligned_String): Remove.  All uses
replaced by struct Lisp_Cons and struct Lisp_String, since they
are now properly aligned.
(USE_STACK_CONS, USE_STACK_STRING): Simplify now that we can
assume struct Lisp_Cons and struct Lisp_String are properly
aligned.
parent 5d68dc9a
...@@ -667,9 +667,7 @@ close_emacs_globals (ptrdiff_t num_symbols) ...@@ -667,9 +667,7 @@ close_emacs_globals (ptrdiff_t num_symbols)
"#ifndef DEFINE_SYMBOLS\n" "#ifndef DEFINE_SYMBOLS\n"
"extern\n" "extern\n"
"#endif\n" "#endif\n"
"struct {\n" "struct Lisp_Symbol lispsym[%td];\n"),
" struct GCALIGNED Lisp_Symbol s;\n"
"} lispsym[%td];\n"),
num_symbols); num_symbols);
} }
......
...@@ -211,9 +211,9 @@ alloc_unexec_post (void) ...@@ -211,9 +211,9 @@ alloc_unexec_post (void)
/* Mark, unmark, query mark bit of a Lisp string. S must be a pointer /* Mark, unmark, query mark bit of a Lisp string. S must be a pointer
to a struct Lisp_String. */ to a struct Lisp_String. */
#define MARK_STRING(S) ((S)->size |= ARRAY_MARK_FLAG) #define MARK_STRING(S) ((S)->u.s.size |= ARRAY_MARK_FLAG)
#define UNMARK_STRING(S) ((S)->size &= ~ARRAY_MARK_FLAG) #define UNMARK_STRING(S) ((S)->u.s.size &= ~ARRAY_MARK_FLAG)
#define STRING_MARKED_P(S) (((S)->size & ARRAY_MARK_FLAG) != 0) #define STRING_MARKED_P(S) (((S)->u.s.size & ARRAY_MARK_FLAG) != 0)
#define VECTOR_MARK(V) ((V)->header.size |= ARRAY_MARK_FLAG) #define VECTOR_MARK(V) ((V)->header.size |= ARRAY_MARK_FLAG)
#define VECTOR_UNMARK(V) ((V)->header.size &= ~ARRAY_MARK_FLAG) #define VECTOR_UNMARK(V) ((V)->header.size &= ~ARRAY_MARK_FLAG)
...@@ -1730,14 +1730,14 @@ static EMACS_INT total_string_bytes; ...@@ -1730,14 +1730,14 @@ static EMACS_INT total_string_bytes;
string_free_list, return a pointer to its successor in the string_free_list, return a pointer to its successor in the
free-list. */ free-list. */
#define NEXT_FREE_LISP_STRING(S) (*(struct Lisp_String **) (S)) #define NEXT_FREE_LISP_STRING(S) ((S)->u.next)
/* Return a pointer to the sdata structure belonging to Lisp string S. /* Return a pointer to the sdata structure belonging to Lisp string S.
S must be live, i.e. S->data must not be null. S->data is actually S must be live, i.e. S->data must not be null. S->data is actually
a pointer to the `u.data' member of its sdata structure; the a pointer to the `u.data' member of its sdata structure; the
structure starts at a constant offset in front of that. */ structure starts at a constant offset in front of that. */
#define SDATA_OF_STRING(S) ((sdata *) ((S)->data - SDATA_DATA_OFFSET)) #define SDATA_OF_STRING(S) ((sdata *) ((S)->u.s.data - SDATA_DATA_OFFSET))
#ifdef GC_CHECK_STRING_OVERRUN #ifdef GC_CHECK_STRING_OVERRUN
...@@ -1818,9 +1818,10 @@ ptrdiff_t ...@@ -1818,9 +1818,10 @@ ptrdiff_t
string_bytes (struct Lisp_String *s) string_bytes (struct Lisp_String *s)
{ {
ptrdiff_t nbytes = ptrdiff_t nbytes =
(s->size_byte < 0 ? s->size & ~ARRAY_MARK_FLAG : s->size_byte); (s->u.s.size_byte < 0 ? s->u.s.size & ~ARRAY_MARK_FLAG : s->u.s.size_byte);
if (!PURE_P (s) && s->data && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s))) if (!PURE_P (s) && s->u.s.data
&& nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
emacs_abort (); emacs_abort ();
return nbytes; return nbytes;
} }
...@@ -1926,7 +1927,7 @@ allocate_string (void) ...@@ -1926,7 +1927,7 @@ allocate_string (void)
{ {
s = b->strings + i; s = b->strings + i;
/* Every string on a free list should have NULL data pointer. */ /* Every string on a free list should have NULL data pointer. */
s->data = NULL; s->u.s.data = NULL;
NEXT_FREE_LISP_STRING (s) = string_free_list; NEXT_FREE_LISP_STRING (s) = string_free_list;
string_free_list = s; string_free_list = s;
} }
...@@ -1965,10 +1966,10 @@ allocate_string (void) ...@@ -1965,10 +1966,10 @@ allocate_string (void)
/* Set up Lisp_String S for holding NCHARS characters, NBYTES bytes, /* Set up Lisp_String S for holding NCHARS characters, NBYTES bytes,
plus a NUL byte at the end. Allocate an sdata structure for S, and plus a NUL byte at the end. Allocate an sdata structure DATA for
set S->data to its `u.data' member. Store a NUL byte at the end of S, and set S->u.s.data to SDATA->u.data. Store a NUL byte at the
S->data. Set S->size to NCHARS and S->size_byte to NBYTES. Free end of S->u.s.data. Set S->u.s.size to NCHARS and S->u.s.size_byte
S->data if it was initially non-null. */ to NBYTES. Free S->u.s.data if it was initially non-null. */
void void
allocate_string_data (struct Lisp_String *s, allocate_string_data (struct Lisp_String *s,
...@@ -1984,7 +1985,7 @@ allocate_string_data (struct Lisp_String *s, ...@@ -1984,7 +1985,7 @@ allocate_string_data (struct Lisp_String *s,
/* Determine the number of bytes needed to store NBYTES bytes /* Determine the number of bytes needed to store NBYTES bytes
of string data. */ of string data. */
needed = SDATA_SIZE (nbytes); needed = SDATA_SIZE (nbytes);
if (s->data) if (s->u.s.data)
{ {
old_data = SDATA_OF_STRING (s); old_data = SDATA_OF_STRING (s);
old_nbytes = STRING_BYTES (s); old_nbytes = STRING_BYTES (s);
...@@ -2043,13 +2044,13 @@ allocate_string_data (struct Lisp_String *s, ...@@ -2043,13 +2044,13 @@ allocate_string_data (struct Lisp_String *s,
MALLOC_UNBLOCK_INPUT; MALLOC_UNBLOCK_INPUT;
s->data = SDATA_DATA (data); s->u.s.data = SDATA_DATA (data);
#ifdef GC_CHECK_STRING_BYTES #ifdef GC_CHECK_STRING_BYTES
SDATA_NBYTES (data) = nbytes; SDATA_NBYTES (data) = nbytes;
#endif #endif
s->size = nchars; s->u.s.size = nchars;
s->size_byte = nbytes; s->u.s.size_byte = nbytes;
s->data[nbytes] = '\0'; s->u.s.data[nbytes] = '\0';
#ifdef GC_CHECK_STRING_OVERRUN #ifdef GC_CHECK_STRING_OVERRUN
memcpy ((char *) data + needed, string_overrun_cookie, memcpy ((char *) data + needed, string_overrun_cookie,
GC_STRING_OVERRUN_COOKIE_SIZE); GC_STRING_OVERRUN_COOKIE_SIZE);
...@@ -2093,7 +2094,7 @@ sweep_strings (void) ...@@ -2093,7 +2094,7 @@ sweep_strings (void)
{ {
struct Lisp_String *s = b->strings + i; struct Lisp_String *s = b->strings + i;
if (s->data) if (s->u.s.data)
{ {
/* String was not on free-list before. */ /* String was not on free-list before. */
if (STRING_MARKED_P (s)) if (STRING_MARKED_P (s))
...@@ -2102,7 +2103,7 @@ sweep_strings (void) ...@@ -2102,7 +2103,7 @@ sweep_strings (void)
UNMARK_STRING (s); UNMARK_STRING (s);
/* Do not use string_(set|get)_intervals here. */ /* Do not use string_(set|get)_intervals here. */
s->intervals = balance_intervals (s->intervals); s->u.s.intervals = balance_intervals (s->u.s.intervals);
++total_strings; ++total_strings;
total_string_bytes += STRING_BYTES (s); total_string_bytes += STRING_BYTES (s);
...@@ -2125,7 +2126,7 @@ sweep_strings (void) ...@@ -2125,7 +2126,7 @@ sweep_strings (void)
/* Reset the strings's `data' member so that we /* Reset the strings's `data' member so that we
know it's free. */ know it's free. */
s->data = NULL; s->u.s.data = NULL;
/* Put the string on the free-list. */ /* Put the string on the free-list. */
NEXT_FREE_LISP_STRING (s) = string_free_list; NEXT_FREE_LISP_STRING (s) = string_free_list;
...@@ -2264,7 +2265,7 @@ compact_small_strings (void) ...@@ -2264,7 +2265,7 @@ compact_small_strings (void)
{ {
eassert (tb != b || to < from); eassert (tb != b || to < from);
memmove (to, from, nbytes + GC_STRING_EXTRA); memmove (to, from, nbytes + GC_STRING_EXTRA);
to->string->data = SDATA_DATA (to); to->string->u.s.data = SDATA_DATA (to);
} }
/* Advance past the sdata we copied to. */ /* Advance past the sdata we copied to. */
...@@ -2544,7 +2545,7 @@ make_uninit_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes) ...@@ -2544,7 +2545,7 @@ make_uninit_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes)
return empty_multibyte_string; return empty_multibyte_string;
s = allocate_string (); s = allocate_string ();
s->intervals = NULL; s->u.s.intervals = NULL;
allocate_string_data (s, nchars, nbytes); allocate_string_data (s, nchars, nbytes);
XSETSTRING (string, s); XSETSTRING (string, s);
string_chars_consed += nbytes; string_chars_consed += nbytes;
...@@ -2729,8 +2730,8 @@ static struct Lisp_Cons *cons_free_list; ...@@ -2729,8 +2730,8 @@ static struct Lisp_Cons *cons_free_list;
void void
free_cons (struct Lisp_Cons *ptr) free_cons (struct Lisp_Cons *ptr)
{ {
ptr->u.chain = cons_free_list; ptr->u.s.u.chain = cons_free_list;
ptr->car = Vdead; ptr->u.s.car = Vdead;
cons_free_list = ptr; cons_free_list = ptr;
consing_since_gc -= sizeof *ptr; consing_since_gc -= sizeof *ptr;
total_free_conses++; total_free_conses++;
...@@ -2749,7 +2750,7 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0, ...@@ -2749,7 +2750,7 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
/* We use the cdr for chaining the free list /* We use the cdr for chaining the free list
so that we won't use the same field that has the mark bit. */ so that we won't use the same field that has the mark bit. */
XSETCONS (val, cons_free_list); XSETCONS (val, cons_free_list);
cons_free_list = cons_free_list->u.chain; cons_free_list = cons_free_list->u.s.u.chain;
} }
else else
{ {
...@@ -2786,7 +2787,7 @@ check_cons_list (void) ...@@ -2786,7 +2787,7 @@ check_cons_list (void)
struct Lisp_Cons *tail = cons_free_list; struct Lisp_Cons *tail = cons_free_list;
while (tail) while (tail)
tail = tail->u.chain; tail = tail->u.s.u.chain;
} }
#endif #endif
...@@ -3543,27 +3544,17 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT ...@@ -3543,27 +3544,17 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT
Symbol Allocation Symbol Allocation
***********************************************************************/ ***********************************************************************/
/* Like struct Lisp_Symbol, but padded so that the size is a multiple
of the required alignment. */
union aligned_Lisp_Symbol
{
struct Lisp_Symbol s;
unsigned char c[(sizeof (struct Lisp_Symbol) + GCALIGNMENT - 1)
& -GCALIGNMENT];
};
/* Each symbol_block is just under 1020 bytes long, since malloc /* Each symbol_block is just under 1020 bytes long, since malloc
really allocates in units of powers of two and uses 4 bytes for its really allocates in units of powers of two and uses 4 bytes for its
own overhead. */ own overhead. */
#define SYMBOL_BLOCK_SIZE \ #define SYMBOL_BLOCK_SIZE \
((1020 - sizeof (struct symbol_block *)) / sizeof (union aligned_Lisp_Symbol)) ((1020 - sizeof (struct symbol_block *)) / sizeof (struct Lisp_Symbol))
struct symbol_block struct symbol_block
{ {
/* Place `symbols' first, to preserve alignment. */ /* Place `symbols' first, to preserve alignment. */
union aligned_Lisp_Symbol symbols[SYMBOL_BLOCK_SIZE]; struct Lisp_Symbol symbols[SYMBOL_BLOCK_SIZE];
struct symbol_block *next; struct symbol_block *next;
}; };
...@@ -3587,7 +3578,7 @@ static struct Lisp_Symbol *symbol_free_list; ...@@ -3587,7 +3578,7 @@ static struct Lisp_Symbol *symbol_free_list;
static void static void
set_symbol_name (Lisp_Object sym, Lisp_Object name) set_symbol_name (Lisp_Object sym, Lisp_Object name)
{ {
XSYMBOL (sym)->name = name; XSYMBOL (sym)->u.s.name = name;
} }
void void
...@@ -3596,15 +3587,15 @@ init_symbol (Lisp_Object val, Lisp_Object name) ...@@ -3596,15 +3587,15 @@ init_symbol (Lisp_Object val, Lisp_Object name)
struct Lisp_Symbol *p = XSYMBOL (val); struct Lisp_Symbol *p = XSYMBOL (val);
set_symbol_name (val, name); set_symbol_name (val, name);
set_symbol_plist (val, Qnil); set_symbol_plist (val, Qnil);
p->redirect = SYMBOL_PLAINVAL; p->u.s.redirect = SYMBOL_PLAINVAL;
SET_SYMBOL_VAL (p, Qunbound); SET_SYMBOL_VAL (p, Qunbound);
set_symbol_function (val, Qnil); set_symbol_function (val, Qnil);
set_symbol_next (val, NULL); set_symbol_next (val, NULL);
p->gcmarkbit = false; p->u.s.gcmarkbit = false;
p->interned = SYMBOL_UNINTERNED; p->u.s.interned = SYMBOL_UNINTERNED;
p->trapped_write = SYMBOL_UNTRAPPED_WRITE; p->u.s.trapped_write = SYMBOL_UNTRAPPED_WRITE;
p->declared_special = false; p->u.s.declared_special = false;
p->pinned = false; p->u.s.pinned = false;
} }
DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0, DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
...@@ -3621,7 +3612,7 @@ Its value is void, and its function definition and property list are nil. */) ...@@ -3621,7 +3612,7 @@ Its value is void, and its function definition and property list are nil. */)
if (symbol_free_list) if (symbol_free_list)
{ {
XSETSYMBOL (val, symbol_free_list); XSETSYMBOL (val, symbol_free_list);
symbol_free_list = symbol_free_list->next; symbol_free_list = symbol_free_list->u.s.next;
} }
else else
{ {
...@@ -3634,7 +3625,7 @@ Its value is void, and its function definition and property list are nil. */) ...@@ -3634,7 +3625,7 @@ Its value is void, and its function definition and property list are nil. */)
symbol_block_index = 0; symbol_block_index = 0;
total_free_symbols += SYMBOL_BLOCK_SIZE; total_free_symbols += SYMBOL_BLOCK_SIZE;
} }
XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index].s); XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index]);
symbol_block_index++; symbol_block_index++;
} }
...@@ -4587,7 +4578,7 @@ live_string_holding (struct mem_node *m, void *p) ...@@ -4587,7 +4578,7 @@ live_string_holding (struct mem_node *m, void *p)
if (0 <= offset && offset < STRING_BLOCK_SIZE * sizeof b->strings[0]) if (0 <= offset && offset < STRING_BLOCK_SIZE * sizeof b->strings[0])
{ {
struct Lisp_String *s = p = cp -= offset % sizeof b->strings[0]; struct Lisp_String *s = p = cp -= offset % sizeof b->strings[0];
if (s->data) if (s->u.s.data)
return make_lisp_ptr (s, Lisp_String); return make_lisp_ptr (s, Lisp_String);
} }
} }
...@@ -4621,7 +4612,7 @@ live_cons_holding (struct mem_node *m, void *p) ...@@ -4621,7 +4612,7 @@ live_cons_holding (struct mem_node *m, void *p)
|| offset / sizeof b->conses[0] < cons_block_index)) || offset / sizeof b->conses[0] < cons_block_index))
{ {
struct Lisp_Cons *s = p = cp -= offset % sizeof b->conses[0]; struct Lisp_Cons *s = p = cp -= offset % sizeof b->conses[0];
if (!EQ (s->car, Vdead)) if (!EQ (s->u.s.car, Vdead))
return make_lisp_ptr (s, Lisp_Cons); return make_lisp_ptr (s, Lisp_Cons);
} }
} }
...@@ -4656,7 +4647,7 @@ live_symbol_holding (struct mem_node *m, void *p) ...@@ -4656,7 +4647,7 @@ live_symbol_holding (struct mem_node *m, void *p)
|| offset / sizeof b->symbols[0] < symbol_block_index)) || offset / sizeof b->symbols[0] < symbol_block_index))
{ {
struct Lisp_Symbol *s = p = cp -= offset % sizeof b->symbols[0]; struct Lisp_Symbol *s = p = cp -= offset % sizeof b->symbols[0];
if (!EQ (s->function, Vdead)) if (!EQ (s->u.s.function, Vdead))
return make_lisp_symbol (s); return make_lisp_symbol (s);
} }
} }
...@@ -4984,7 +4975,7 @@ mark_memory (void *start, void *end) ...@@ -4984,7 +4975,7 @@ mark_memory (void *start, void *end)
Lisp_Object obj = build_string ("test"); Lisp_Object obj = build_string ("test");
struct Lisp_String *s = XSTRING (obj); struct Lisp_String *s = XSTRING (obj);
Fgarbage_collect (); Fgarbage_collect ();
fprintf (stderr, "test '%s'\n", s->data); fprintf (stderr, "test '%s'\n", s->u.s.data);
return Qnil; return Qnil;
} }
...@@ -5484,16 +5475,16 @@ make_pure_string (const char *data, ...@@ -5484,16 +5475,16 @@ make_pure_string (const char *data,
{ {
Lisp_Object string; Lisp_Object string;
struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String); struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
s->data = (unsigned char *) find_string_data_in_pure (data, nbytes); s->u.s.data = (unsigned char *) find_string_data_in_pure (data, nbytes);
if (s->data == NULL) if (s->u.s.data == NULL)
{ {
s->data = pure_alloc (nbytes + 1, -1); s->u.s.data = pure_alloc (nbytes + 1, -1);
memcpy (s->data, data, nbytes); memcpy (s->u.s.data, data, nbytes);
s->data[nbytes] = '\0'; s->u.s.data[nbytes] = '\0';
} }
s->size = nchars; s->u.s.size = nchars;
s->size_byte = multibyte ? nbytes : -1; s->u.s.size_byte = multibyte ? nbytes : -1;
s->intervals = NULL; s->u.s.intervals = NULL;
XSETSTRING (string, s); XSETSTRING (string, s);
return string; return string;
} }
...@@ -5506,10 +5497,10 @@ make_pure_c_string (const char *data, ptrdiff_t nchars) ...@@ -5506,10 +5497,10 @@ make_pure_c_string (const char *data, ptrdiff_t nchars)
{ {
Lisp_Object string; Lisp_Object string;
struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String); struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
s->size = nchars; s->u.s.size = nchars;
s->size_byte = -1; s->u.s.size_byte = -1;
s->data = (unsigned char *) data; s->u.s.data = (unsigned char *) data;
s->intervals = NULL; s->u.s.intervals = NULL;
XSETSTRING (string, s); XSETSTRING (string, s);
return string; return string;
} }
...@@ -5620,7 +5611,7 @@ purecopy (Lisp_Object obj) ...@@ -5620,7 +5611,7 @@ purecopy (Lisp_Object obj)
|| SUBRP (obj)) || SUBRP (obj))
return obj; /* Already pure. */ return obj; /* Already pure. */
if (STRINGP (obj) && XSTRING (obj)->intervals) if (STRINGP (obj) && XSTRING (obj)->u.s.intervals)
message_with_string ("Dropping text-properties while making string `%s' pure", message_with_string ("Dropping text-properties while making string `%s' pure",
obj, true); obj, true);
...@@ -5675,10 +5666,10 @@ purecopy (Lisp_Object obj) ...@@ -5675,10 +5666,10 @@ purecopy (Lisp_Object obj)
} }
else if (SYMBOLP (obj)) else if (SYMBOLP (obj))
{ {
if (!XSYMBOL (obj)->pinned && !c_symbol_p (XSYMBOL (obj))) if (!XSYMBOL (obj)->u.s.pinned && !c_symbol_p (XSYMBOL (obj)))
{ /* We can't purify them, but they appear in many pure objects. { /* We can't purify them, but they appear in many pure objects.
Mark them as `pinned' so we know to mark them at every GC cycle. */ Mark them as `pinned' so we know to mark them at every GC cycle. */
XSYMBOL (obj)->pinned = true; XSYMBOL (obj)->u.s.pinned = true;
symbol_block_pinned = symbol_block; symbol_block_pinned = symbol_block;
} }
/* Don't hash-cons it. */ /* Don't hash-cons it. */
...@@ -5891,10 +5882,10 @@ mark_pinned_symbols (void) ...@@ -5891,10 +5882,10 @@ mark_pinned_symbols (void)
for (sblk = symbol_block_pinned; sblk; sblk = sblk->next) for (sblk = symbol_block_pinned; sblk; sblk = sblk->next)
{ {
union aligned_Lisp_Symbol *sym = sblk->symbols, *end = sym + lim; struct Lisp_Symbol *sym = sblk->symbols, *end = sym + lim;
for (; sym < end; ++sym) for (; sym < end; ++sym)
if (sym->s.pinned) if (sym->u.s.pinned)
mark_object (make_lisp_symbol (&sym->s)); mark_object (make_lisp_symbol (sym));
lim = SYMBOL_BLOCK_SIZE; lim = SYMBOL_BLOCK_SIZE;
} }
...@@ -6256,7 +6247,7 @@ mark_char_table (struct Lisp_Vector *ptr, enum pvec_type pvectype) ...@@ -6256,7 +6247,7 @@ mark_char_table (struct Lisp_Vector *ptr, enum pvec_type pvectype)
{ {
Lisp_Object val = ptr->contents[i]; Lisp_Object val = ptr->contents[i];
if (INTEGERP (val) || (SYMBOLP (val) && XSYMBOL (val)->gcmarkbit)) if (INTEGERP (val) || (SYMBOLP (val) && XSYMBOL (val)->u.s.gcmarkbit))
continue; continue;
if (SUB_CHAR_TABLE_P (val)) if (SUB_CHAR_TABLE_P (val))
{ {
...@@ -6499,7 +6490,7 @@ mark_object (Lisp_Object arg) ...@@ -6499,7 +6490,7 @@ mark_object (Lisp_Object arg)
break; break;
CHECK_ALLOCATED_AND_LIVE (live_string_p); CHECK_ALLOCATED_AND_LIVE (live_string_p);
MARK_STRING (ptr); MARK_STRING (ptr);
MARK_INTERVAL_TREE (ptr->intervals); MARK_INTERVAL_TREE (ptr->u.s.intervals);
#ifdef GC_CHECK_STRING_BYTES #ifdef GC_CHECK_STRING_BYTES
/* Check that the string size recorded in the string is the /* Check that the string size recorded in the string is the
same as the one recorded in the sdata structure. */ same as the one recorded in the sdata structure. */
...@@ -6640,17 +6631,17 @@ mark_object (Lisp_Object arg) ...@@ -6640,17 +6631,17 @@ mark_object (Lisp_Object arg)
case Lisp_Symbol: case Lisp_Symbol:
{ {
register struct Lisp_Symbol *ptr = XSYMBOL (obj); struct Lisp_Symbol *ptr = XSYMBOL (obj);
nextsym: nextsym:
if (ptr->gcmarkbit) if (ptr->u.s.gcmarkbit)
break; break;
CHECK_ALLOCATED_AND_LIVE_SYMBOL (); CHECK_ALLOCATED_AND_LIVE_SYMBOL ();
ptr->gcmarkbit = 1; ptr->u.s.gcmarkbit = 1;
/* Attempt to catch bogus objects. */ /* Attempt to catch bogus objects. */
eassert (valid_lisp_object_p (ptr->function)); eassert (valid_lisp_object_p (ptr->u.s.function));
mark_object (ptr->function); mark_object (ptr->u.s.function);
mark_object (ptr->plist); mark_object (ptr->u.s.plist);
switch (ptr->redirect) switch (ptr->u.s.redirect)
{ {
case SYMBOL_PLAINVAL: mark_object (SYMBOL_VAL (ptr)); break; case SYMBOL_PLAINVAL: mark_object (SYMBOL_VAL (ptr)); break;
case SYMBOL_VARALIAS: case SYMBOL_VARALIAS:
...@@ -6671,11 +6662,11 @@ mark_object (Lisp_Object arg) ...@@ -6671,11 +6662,11 @@ mark_object (Lisp_Object arg)
break; break;
default: emacs_abort (); default: emacs_abort ();
} }
if (!PURE_P (XSTRING (ptr->name))) if (!PURE_P (XSTRING (ptr->u.s.name)))
MARK_STRING (XSTRING (ptr->name)); MARK_STRING (XSTRING (ptr->u.s.name));
MARK_INTERVAL_TREE (string_intervals (ptr->name)); MARK_INTERVAL_TREE (string_intervals (ptr->u.s.name));
/* Inner loop to mark next symbol in this bucket, if any. */ /* Inner loop to mark next symbol in this bucket, if any. */
po = ptr = ptr->next; po = ptr = ptr->u.s.next;
if (ptr) if (ptr)
goto nextsym; goto nextsym;
} }
...@@ -6729,14 +6720,14 @@ mark_object (Lisp_Object arg) ...@@ -6729,14 +6720,14 @@ mark_object (Lisp_Object arg)
CHECK_ALLOCATED_AND_LIVE (live_cons_p); CHECK_ALLOCATED_AND_LIVE (live_cons_p);
CONS_MARK (ptr); CONS_MARK (ptr);
/* If the cdr is nil, avoid recursion for the car. */ /* If the cdr is nil, avoid recursion for the car. */
if (EQ (ptr->u.cdr, Qnil)) if (EQ (ptr->u.s.u.cdr, Qnil))
{ {
obj = ptr->car; obj = ptr->u.s.car;
cdr_count = 0; cdr_count = 0;
goto loop; goto loop;
} }
mark_object (ptr->car); mark_object (ptr->u.s.car);
obj = ptr->u.cdr; obj = ptr->u.s.u.cdr;
cdr_count++; cdr_count++;
if (cdr_count == mark_object_loop_halt) if (cdr_count == mark_object_loop_halt)
emacs_abort (); emacs_abort ();
...@@ -6797,7 +6788,7 @@ survives_gc_p (Lisp_Object obj) ...@@ -6797,7 +6788,7 @@ survives_gc_p (Lisp_Object obj)
break; break;
case Lisp_Symbol: case Lisp_Symbol:
survives_p = XSYMBOL (obj)->gcmarkbit; survives_p = XSYMBOL (obj)->u.s.gcmarkbit;
break; break;
case Lisp_Misc: case Lisp_Misc:
...@@ -6873,9 +6864,9 @@ sweep_conses (void) ...@@ -6873,9 +6864,9 @@ sweep_conses (void)
if (!CONS_MARKED_P (&cblk->conses[pos])) if (!CONS_MARKED_P (&cblk->conses[pos]))
{ {
this_free++; this_free++;
cblk->conses[pos].u.chain = cons_free_list; cblk->conses[pos].u.s.u.chain = cons_free_list;
cons_free_list = &cblk->conses[pos]; cons_free_list = &cblk->conses[pos];
cons_free_list->car = Vdead; cons_free_list->u.s.car = Vdead;
} }