diff options
author | Paul Eggert <[email protected]> | 2011-04-25 00:14:46 -0700 |
---|---|---|
committer | Paul Eggert <[email protected]> | 2011-04-25 00:14:46 -0700 |
commit | eab3844f965646b62e242aa622754b86d1fd3444 (patch) | |
tree | 10246105e5facc5d61ccf797dfa05debdb1877c1 /src/alloc.c | |
parent | 0df1eac54fdf82a80a7611fe421d94a23ebd4a0a (diff) |
lisp.h: Fix a problem with aliasing and vector headers.
GCC 4.6.0 optimizes based on type-based alias analysis. For
example, if b is of type struct buffer * and v of type struct
Lisp_Vector *, then gcc -O2 was incorrectly assuming that &b->size
!= &v->size, and therefore "v->size = 1; b->size = 2; return
v->size;" must therefore return 1. This assumption is incorrect
for Emacs, since it type-puns struct Lisp_Vector * with many other
types. To fix this problem, this patch adds a new type struct
vector_header that documents the constraints on layout of vectors
and pseudovectors, and helps optimizing compilers not get fooled
by Emacs's type punning. It also adds the macros XSETTYPED_PVECTYPE
XSETTYPED_PSEUDOVECTOR, TYPED_PSEUDOVECTORP, for similar reasons.
* lisp.h (XVECTOR_SIZE): New convenience macro. All previous uses of
XVECTOR (foo)->size replaced to use this macro, to avoid the hassle
of writing XVECTOR (foo)->header.size.
(XVECTOR_HEADER_SIZE): New macro, for use in XSETPSEUDOVECTOR.
(XSETTYPED_PVECTYPE): New macro, specifying the name of the size
member.
(XSETPVECTYPE): Rewrite in terms of new macro.
(XSETPVECTYPESIZE): New macro, specifying both type and size.
This is a bit clearer, and further avoids the possibility of
undesirable aliasing.
(XSETTYPED_PSEUDOVECTOR): New macro, specifying the size.
(XSETPSEUDOVECTOR): Rewrite in terms of XSETTYPED_PSEUDOVECTOR
and XVECTOR_HEADER_SIZE.
(XSETSUBR): Rewrite in terms of XSETTYPED_PSEUDOVECTOR and XSIZE,
since Lisp_Subr is a special case (no "next" field).
(ASIZE): Rewrite in terms of XVECTOR_SIZE.
(struct vector_header): New type.
(TYPED_PSEUDOVECTORP): New macro, also specifying the C type of the
object, to help avoid aliasing.
(PSEUDOVECTORP): Rewrite in terms of TYPED_PSEUDOVECTORP.
(SUBRP): Likewise, since Lisp_Subr is a special case.
* lisp.h (struct Lisp_Vector, struct Lisp_Char_Table):
(struct Lisp_Sub_Char_Table, struct Lisp_Bool_Vector):
(struct Lisp_Hash_Table): Combine first two members into a single
struct vector_header member. All uses of "size" and "next" members
changed to be "header.size" and "header.next".
* buffer.h (struct buffer): Likewise.
* font.h (struct font_spec, struct font_entity, struct font): Likewise.
* frame.h (struct frame): Likewise.
* process.h (struct Lisp_Process): Likewise.
* termhooks.h (struct terminal): Likewise.
* window.c (struct save_window_data, struct saved_window): Likewise.
* window.h (struct window): Likewise.
* alloc.c (allocate_buffer, Fmake_bool_vector, allocate_pseudovector):
Use XSETPVECTYPESIZE, not XSETPVECTYPE, to avoid aliasing problems.
* buffer.c (init_buffer_once): Likewise.
* lread.c (defsubr): Use XSETTYPED_PVECTYPE, since Lisp_Subr is a
special case.
* process.c (Fformat_network_address): Use local var for size,
for brevity.
Diffstat (limited to 'src/alloc.c')
-rw-r--r-- | src/alloc.c | 63 |
1 files changed, 30 insertions, 33 deletions
diff --git a/src/alloc.c b/src/alloc.c index dd27303428..c9496ecf25 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -146,9 +146,9 @@ static pthread_mutex_t alloc_mutex; #define UNMARK_STRING(S) ((S)->size &= ~ARRAY_MARK_FLAG) #define STRING_MARKED_P(S) (((S)->size & ARRAY_MARK_FLAG) != 0) -#define VECTOR_MARK(V) ((V)->size |= ARRAY_MARK_FLAG) -#define VECTOR_UNMARK(V) ((V)->size &= ~ARRAY_MARK_FLAG) -#define VECTOR_MARKED_P(V) (((V)->size & ARRAY_MARK_FLAG) != 0) +#define VECTOR_MARK(V) ((V)->header.size |= ARRAY_MARK_FLAG) +#define VECTOR_UNMARK(V) ((V)->header.size &= ~ARRAY_MARK_FLAG) +#define VECTOR_MARKED_P(V) (((V)->header.size & ARRAY_MARK_FLAG) != 0) /* Value is the number of bytes of S, a pointer to a struct Lisp_String. Be careful during GC, because S->size contains the mark bit for @@ -1055,9 +1055,9 @@ allocate_buffer (void) struct buffer *b = (struct buffer *) lisp_malloc (sizeof (struct buffer), MEM_TYPE_BUFFER); - b->size = ((sizeof (struct buffer) + sizeof (EMACS_INT) - 1) - / sizeof (EMACS_INT)); - XSETPVECTYPE (b, PVEC_BUFFER); + XSETPVECTYPESIZE (b, PVEC_BUFFER, + ((sizeof (struct buffer) + sizeof (EMACS_INT) - 1) + / sizeof (EMACS_INT))); return b; } @@ -2244,10 +2244,8 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) slot `size' of the struct Lisp_Bool_Vector. */ val = Fmake_vector (make_number (length_in_elts + 1), Qnil); - /* Get rid of any bits that would cause confusion. */ - XVECTOR (val)->size = 0; /* No Lisp_Object to trace in there. */ - /* Use XVECTOR (val) rather than `p' because p->size is not TRT. */ - XSETPVECTYPE (XVECTOR (val), PVEC_BOOL_VECTOR); + /* No Lisp_Object to trace in there. */ + XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0); p = XBOOL_VECTOR (val); p->size = XFASTINT (length); @@ -2814,7 +2812,7 @@ allocate_vectorlike (EMACS_INT len) consing_since_gc += nbytes; vector_cells_consed += len; - p->next = all_vectors; + p->header.next.vector = all_vectors; all_vectors = p; MALLOC_UNBLOCK_INPUT; @@ -2830,7 +2828,7 @@ struct Lisp_Vector * allocate_vector (EMACS_INT nslots) { struct Lisp_Vector *v = allocate_vectorlike (nslots); - v->size = nslots; + v->header.size = nslots; return v; } @@ -2844,11 +2842,10 @@ allocate_pseudovector (int memlen, int lisplen, EMACS_INT tag) EMACS_INT i; /* Only the first lisplen slots will be traced normally by the GC. */ - v->size = lisplen; for (i = 0; i < lisplen; ++i) v->contents[i] = Qnil; - XSETPVECTYPE (v, tag); /* Add the appropriate tag. */ + XSETPVECTYPESIZE (v, tag, lisplen); return v; } @@ -4737,7 +4734,7 @@ make_pure_vector (EMACS_INT len) p = (struct Lisp_Vector *) pure_alloc (size, Lisp_Vectorlike); XSETVECTOR (new, p); - XVECTOR (new)->size = len; + XVECTOR (new)->header.size = len; return new; } @@ -4775,7 +4772,7 @@ Does not copy symbols. Copies strings without text properties. */) register EMACS_INT i; EMACS_INT size; - size = XVECTOR (obj)->size; + size = XVECTOR_SIZE (obj); if (size & PSEUDOVECTOR_FLAG) size &= PSEUDOVECTOR_SIZE_MASK; vec = XVECTOR (make_pure_vector (size)); @@ -4899,7 +4896,7 @@ returns nil, because real GC can't be done. */) } } - nextb = nextb->next; + nextb = nextb->header.next.buffer; } } @@ -5054,7 +5051,7 @@ returns nil, because real GC can't be done. */) undo_list any more, we can finally mark the list. */ mark_object (nextb->BUFFER_INTERNAL_FIELD (undo_list)); - nextb = nextb->next; + nextb = nextb->header.next.buffer; } } @@ -5228,7 +5225,7 @@ static size_t mark_object_loop_halt; static void mark_vectorlike (struct Lisp_Vector *ptr) { - register EMACS_UINT size = ptr->size; + register EMACS_UINT size = ptr->header.size; register EMACS_UINT i; eassert (!VECTOR_MARKED_P (ptr)); @@ -5251,7 +5248,7 @@ mark_vectorlike (struct Lisp_Vector *ptr) static void mark_char_table (struct Lisp_Vector *ptr) { - register EMACS_UINT size = ptr->size & PSEUDOVECTOR_SIZE_MASK; + register EMACS_UINT size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK; register EMACS_UINT i; eassert (!VECTOR_MARKED_P (ptr)); @@ -5364,7 +5361,7 @@ mark_object (Lisp_Object arg) if (po != &buffer_defaults && po != &buffer_local_symbols) { struct buffer *b; - for (b = all_buffers; b && b != po; b = b->next) + for (b = all_buffers; b && b != po; b = b->header.next) ; if (b == NULL) abort (); @@ -5380,7 +5377,7 @@ mark_object (Lisp_Object arg) recursion there. */ { register struct Lisp_Vector *ptr = XVECTOR (obj); - register EMACS_UINT size = ptr->size; + register EMACS_UINT size = ptr->header.size; register EMACS_UINT i; CHECK_LIVE (live_vector_p); @@ -6012,10 +6009,10 @@ gc_sweep (void) if (!VECTOR_MARKED_P (buffer)) { if (prev) - prev->next = buffer->next; + prev->header.next = buffer->header.next; else - all_buffers = buffer->next; - next = buffer->next; + all_buffers = buffer->header.next.buffer; + next = buffer->header.next.buffer; lisp_free (buffer); buffer = next; } @@ -6023,7 +6020,7 @@ gc_sweep (void) { VECTOR_UNMARK (buffer); UNMARK_BALANCE_INTERVALS (BUF_INTERVALS (buffer)); - prev = buffer, buffer = buffer->next; + prev = buffer, buffer = buffer->header.next.buffer; } } @@ -6036,10 +6033,10 @@ gc_sweep (void) if (!VECTOR_MARKED_P (vector)) { if (prev) - prev->next = vector->next; + prev->header.next = vector->header.next; else - all_vectors = vector->next; - next = vector->next; + all_vectors = vector->header.next.vector; + next = vector->header.next.vector; lisp_free (vector); n_vectors--; vector = next; @@ -6048,11 +6045,11 @@ gc_sweep (void) else { VECTOR_UNMARK (vector); - if (vector->size & PSEUDOVECTOR_FLAG) - total_vector_size += (PSEUDOVECTOR_SIZE_MASK & vector->size); + if (vector->header.size & PSEUDOVECTOR_FLAG) + total_vector_size += PSEUDOVECTOR_SIZE_MASK & vector->header.size; else - total_vector_size += vector->size; - prev = vector, vector = vector->next; + total_vector_size += vector->header.size; + prev = vector, vector = vector->header.next.vector; } } |