diff options
| author | Paul Eggert | 2011-04-25 00:14:46 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-04-25 00:14:46 -0700 |
| commit | eab3844f965646b62e242aa622754b86d1fd3444 (patch) | |
| tree | 10246105e5facc5d61ccf797dfa05debdb1877c1 /src/alloc.c | |
| parent | 0df1eac54fdf82a80a7611fe421d94a23ebd4a0a (diff) | |
| download | emacs-eab3844f965646b62e242aa622754b86d1fd3444.tar.gz emacs-eab3844f965646b62e242aa622754b86d1fd3444.zip | |
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 dd27303428f..c9496ecf25c 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -146,9 +146,9 @@ static pthread_mutex_t alloc_mutex; | |||
| 146 | #define UNMARK_STRING(S) ((S)->size &= ~ARRAY_MARK_FLAG) | 146 | #define UNMARK_STRING(S) ((S)->size &= ~ARRAY_MARK_FLAG) |
| 147 | #define STRING_MARKED_P(S) (((S)->size & ARRAY_MARK_FLAG) != 0) | 147 | #define STRING_MARKED_P(S) (((S)->size & ARRAY_MARK_FLAG) != 0) |
| 148 | 148 | ||
| 149 | #define VECTOR_MARK(V) ((V)->size |= ARRAY_MARK_FLAG) | 149 | #define VECTOR_MARK(V) ((V)->header.size |= ARRAY_MARK_FLAG) |
| 150 | #define VECTOR_UNMARK(V) ((V)->size &= ~ARRAY_MARK_FLAG) | 150 | #define VECTOR_UNMARK(V) ((V)->header.size &= ~ARRAY_MARK_FLAG) |
| 151 | #define VECTOR_MARKED_P(V) (((V)->size & ARRAY_MARK_FLAG) != 0) | 151 | #define VECTOR_MARKED_P(V) (((V)->header.size & ARRAY_MARK_FLAG) != 0) |
| 152 | 152 | ||
| 153 | /* Value is the number of bytes of S, a pointer to a struct Lisp_String. | 153 | /* Value is the number of bytes of S, a pointer to a struct Lisp_String. |
| 154 | Be careful during GC, because S->size contains the mark bit for | 154 | Be careful during GC, because S->size contains the mark bit for |
| @@ -1055,9 +1055,9 @@ allocate_buffer (void) | |||
| 1055 | struct buffer *b | 1055 | struct buffer *b |
| 1056 | = (struct buffer *) lisp_malloc (sizeof (struct buffer), | 1056 | = (struct buffer *) lisp_malloc (sizeof (struct buffer), |
| 1057 | MEM_TYPE_BUFFER); | 1057 | MEM_TYPE_BUFFER); |
| 1058 | b->size = ((sizeof (struct buffer) + sizeof (EMACS_INT) - 1) | 1058 | XSETPVECTYPESIZE (b, PVEC_BUFFER, |
| 1059 | / sizeof (EMACS_INT)); | 1059 | ((sizeof (struct buffer) + sizeof (EMACS_INT) - 1) |
| 1060 | XSETPVECTYPE (b, PVEC_BUFFER); | 1060 | / sizeof (EMACS_INT))); |
| 1061 | return b; | 1061 | return b; |
| 1062 | } | 1062 | } |
| 1063 | 1063 | ||
| @@ -2244,10 +2244,8 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) | |||
| 2244 | slot `size' of the struct Lisp_Bool_Vector. */ | 2244 | slot `size' of the struct Lisp_Bool_Vector. */ |
| 2245 | val = Fmake_vector (make_number (length_in_elts + 1), Qnil); | 2245 | val = Fmake_vector (make_number (length_in_elts + 1), Qnil); |
| 2246 | 2246 | ||
| 2247 | /* Get rid of any bits that would cause confusion. */ | 2247 | /* No Lisp_Object to trace in there. */ |
| 2248 | XVECTOR (val)->size = 0; /* No Lisp_Object to trace in there. */ | 2248 | XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0); |
| 2249 | /* Use XVECTOR (val) rather than `p' because p->size is not TRT. */ | ||
| 2250 | XSETPVECTYPE (XVECTOR (val), PVEC_BOOL_VECTOR); | ||
| 2251 | 2249 | ||
| 2252 | p = XBOOL_VECTOR (val); | 2250 | p = XBOOL_VECTOR (val); |
| 2253 | p->size = XFASTINT (length); | 2251 | p->size = XFASTINT (length); |
| @@ -2814,7 +2812,7 @@ allocate_vectorlike (EMACS_INT len) | |||
| 2814 | consing_since_gc += nbytes; | 2812 | consing_since_gc += nbytes; |
| 2815 | vector_cells_consed += len; | 2813 | vector_cells_consed += len; |
| 2816 | 2814 | ||
| 2817 | p->next = all_vectors; | 2815 | p->header.next.vector = all_vectors; |
| 2818 | all_vectors = p; | 2816 | all_vectors = p; |
| 2819 | 2817 | ||
| 2820 | MALLOC_UNBLOCK_INPUT; | 2818 | MALLOC_UNBLOCK_INPUT; |
| @@ -2830,7 +2828,7 @@ struct Lisp_Vector * | |||
| 2830 | allocate_vector (EMACS_INT nslots) | 2828 | allocate_vector (EMACS_INT nslots) |
| 2831 | { | 2829 | { |
| 2832 | struct Lisp_Vector *v = allocate_vectorlike (nslots); | 2830 | struct Lisp_Vector *v = allocate_vectorlike (nslots); |
| 2833 | v->size = nslots; | 2831 | v->header.size = nslots; |
| 2834 | return v; | 2832 | return v; |
| 2835 | } | 2833 | } |
| 2836 | 2834 | ||
| @@ -2844,11 +2842,10 @@ allocate_pseudovector (int memlen, int lisplen, EMACS_INT tag) | |||
| 2844 | EMACS_INT i; | 2842 | EMACS_INT i; |
| 2845 | 2843 | ||
| 2846 | /* Only the first lisplen slots will be traced normally by the GC. */ | 2844 | /* Only the first lisplen slots will be traced normally by the GC. */ |
| 2847 | v->size = lisplen; | ||
| 2848 | for (i = 0; i < lisplen; ++i) | 2845 | for (i = 0; i < lisplen; ++i) |
| 2849 | v->contents[i] = Qnil; | 2846 | v->contents[i] = Qnil; |
| 2850 | 2847 | ||
| 2851 | XSETPVECTYPE (v, tag); /* Add the appropriate tag. */ | 2848 | XSETPVECTYPESIZE (v, tag, lisplen); |
| 2852 | return v; | 2849 | return v; |
| 2853 | } | 2850 | } |
| 2854 | 2851 | ||
| @@ -4737,7 +4734,7 @@ make_pure_vector (EMACS_INT len) | |||
| 4737 | 4734 | ||
| 4738 | p = (struct Lisp_Vector *) pure_alloc (size, Lisp_Vectorlike); | 4735 | p = (struct Lisp_Vector *) pure_alloc (size, Lisp_Vectorlike); |
| 4739 | XSETVECTOR (new, p); | 4736 | XSETVECTOR (new, p); |
| 4740 | XVECTOR (new)->size = len; | 4737 | XVECTOR (new)->header.size = len; |
| 4741 | return new; | 4738 | return new; |
| 4742 | } | 4739 | } |
| 4743 | 4740 | ||
| @@ -4775,7 +4772,7 @@ Does not copy symbols. Copies strings without text properties. */) | |||
| 4775 | register EMACS_INT i; | 4772 | register EMACS_INT i; |
| 4776 | EMACS_INT size; | 4773 | EMACS_INT size; |
| 4777 | 4774 | ||
| 4778 | size = XVECTOR (obj)->size; | 4775 | size = XVECTOR_SIZE (obj); |
| 4779 | if (size & PSEUDOVECTOR_FLAG) | 4776 | if (size & PSEUDOVECTOR_FLAG) |
| 4780 | size &= PSEUDOVECTOR_SIZE_MASK; | 4777 | size &= PSEUDOVECTOR_SIZE_MASK; |
| 4781 | vec = XVECTOR (make_pure_vector (size)); | 4778 | vec = XVECTOR (make_pure_vector (size)); |
| @@ -4899,7 +4896,7 @@ returns nil, because real GC can't be done. */) | |||
| 4899 | } | 4896 | } |
| 4900 | } | 4897 | } |
| 4901 | 4898 | ||
| 4902 | nextb = nextb->next; | 4899 | nextb = nextb->header.next.buffer; |
| 4903 | } | 4900 | } |
| 4904 | } | 4901 | } |
| 4905 | 4902 | ||
| @@ -5054,7 +5051,7 @@ returns nil, because real GC can't be done. */) | |||
| 5054 | undo_list any more, we can finally mark the list. */ | 5051 | undo_list any more, we can finally mark the list. */ |
| 5055 | mark_object (nextb->BUFFER_INTERNAL_FIELD (undo_list)); | 5052 | mark_object (nextb->BUFFER_INTERNAL_FIELD (undo_list)); |
| 5056 | 5053 | ||
| 5057 | nextb = nextb->next; | 5054 | nextb = nextb->header.next.buffer; |
| 5058 | } | 5055 | } |
| 5059 | } | 5056 | } |
| 5060 | 5057 | ||
| @@ -5228,7 +5225,7 @@ static size_t mark_object_loop_halt; | |||
| 5228 | static void | 5225 | static void |
| 5229 | mark_vectorlike (struct Lisp_Vector *ptr) | 5226 | mark_vectorlike (struct Lisp_Vector *ptr) |
| 5230 | { | 5227 | { |
| 5231 | register EMACS_UINT size = ptr->size; | 5228 | register EMACS_UINT size = ptr->header.size; |
| 5232 | register EMACS_UINT i; | 5229 | register EMACS_UINT i; |
| 5233 | 5230 | ||
| 5234 | eassert (!VECTOR_MARKED_P (ptr)); | 5231 | eassert (!VECTOR_MARKED_P (ptr)); |
| @@ -5251,7 +5248,7 @@ mark_vectorlike (struct Lisp_Vector *ptr) | |||
| 5251 | static void | 5248 | static void |
| 5252 | mark_char_table (struct Lisp_Vector *ptr) | 5249 | mark_char_table (struct Lisp_Vector *ptr) |
| 5253 | { | 5250 | { |
| 5254 | register EMACS_UINT size = ptr->size & PSEUDOVECTOR_SIZE_MASK; | 5251 | register EMACS_UINT size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK; |
| 5255 | register EMACS_UINT i; | 5252 | register EMACS_UINT i; |
| 5256 | 5253 | ||
| 5257 | eassert (!VECTOR_MARKED_P (ptr)); | 5254 | eassert (!VECTOR_MARKED_P (ptr)); |
| @@ -5364,7 +5361,7 @@ mark_object (Lisp_Object arg) | |||
| 5364 | if (po != &buffer_defaults && po != &buffer_local_symbols) | 5361 | if (po != &buffer_defaults && po != &buffer_local_symbols) |
| 5365 | { | 5362 | { |
| 5366 | struct buffer *b; | 5363 | struct buffer *b; |
| 5367 | for (b = all_buffers; b && b != po; b = b->next) | 5364 | for (b = all_buffers; b && b != po; b = b->header.next) |
| 5368 | ; | 5365 | ; |
| 5369 | if (b == NULL) | 5366 | if (b == NULL) |
| 5370 | abort (); | 5367 | abort (); |
| @@ -5380,7 +5377,7 @@ mark_object (Lisp_Object arg) | |||
| 5380 | recursion there. */ | 5377 | recursion there. */ |
| 5381 | { | 5378 | { |
| 5382 | register struct Lisp_Vector *ptr = XVECTOR (obj); | 5379 | register struct Lisp_Vector *ptr = XVECTOR (obj); |
| 5383 | register EMACS_UINT size = ptr->size; | 5380 | register EMACS_UINT size = ptr->header.size; |
| 5384 | register EMACS_UINT i; | 5381 | register EMACS_UINT i; |
| 5385 | 5382 | ||
| 5386 | CHECK_LIVE (live_vector_p); | 5383 | CHECK_LIVE (live_vector_p); |
| @@ -6012,10 +6009,10 @@ gc_sweep (void) | |||
| 6012 | if (!VECTOR_MARKED_P (buffer)) | 6009 | if (!VECTOR_MARKED_P (buffer)) |
| 6013 | { | 6010 | { |
| 6014 | if (prev) | 6011 | if (prev) |
| 6015 | prev->next = buffer->next; | 6012 | prev->header.next = buffer->header.next; |
| 6016 | else | 6013 | else |
| 6017 | all_buffers = buffer->next; | 6014 | all_buffers = buffer->header.next.buffer; |
| 6018 | next = buffer->next; | 6015 | next = buffer->header.next.buffer; |
| 6019 | lisp_free (buffer); | 6016 | lisp_free (buffer); |
| 6020 | buffer = next; | 6017 | buffer = next; |
| 6021 | } | 6018 | } |
| @@ -6023,7 +6020,7 @@ gc_sweep (void) | |||
| 6023 | { | 6020 | { |
| 6024 | VECTOR_UNMARK (buffer); | 6021 | VECTOR_UNMARK (buffer); |
| 6025 | UNMARK_BALANCE_INTERVALS (BUF_INTERVALS (buffer)); | 6022 | UNMARK_BALANCE_INTERVALS (BUF_INTERVALS (buffer)); |
| 6026 | prev = buffer, buffer = buffer->next; | 6023 | prev = buffer, buffer = buffer->header.next.buffer; |
| 6027 | } | 6024 | } |
| 6028 | } | 6025 | } |
| 6029 | 6026 | ||
| @@ -6036,10 +6033,10 @@ gc_sweep (void) | |||
| 6036 | if (!VECTOR_MARKED_P (vector)) | 6033 | if (!VECTOR_MARKED_P (vector)) |
| 6037 | { | 6034 | { |
| 6038 | if (prev) | 6035 | if (prev) |
| 6039 | prev->next = vector->next; | 6036 | prev->header.next = vector->header.next; |
| 6040 | else | 6037 | else |
| 6041 | all_vectors = vector->next; | 6038 | all_vectors = vector->header.next.vector; |
| 6042 | next = vector->next; | 6039 | next = vector->header.next.vector; |
| 6043 | lisp_free (vector); | 6040 | lisp_free (vector); |
| 6044 | n_vectors--; | 6041 | n_vectors--; |
| 6045 | vector = next; | 6042 | vector = next; |
| @@ -6048,11 +6045,11 @@ gc_sweep (void) | |||
| 6048 | else | 6045 | else |
| 6049 | { | 6046 | { |
| 6050 | VECTOR_UNMARK (vector); | 6047 | VECTOR_UNMARK (vector); |
| 6051 | if (vector->size & PSEUDOVECTOR_FLAG) | 6048 | if (vector->header.size & PSEUDOVECTOR_FLAG) |
| 6052 | total_vector_size += (PSEUDOVECTOR_SIZE_MASK & vector->size); | 6049 | total_vector_size += PSEUDOVECTOR_SIZE_MASK & vector->header.size; |
| 6053 | else | 6050 | else |
| 6054 | total_vector_size += vector->size; | 6051 | total_vector_size += vector->header.size; |
| 6055 | prev = vector, vector = vector->next; | 6052 | prev = vector, vector = vector->header.next.vector; |
| 6056 | } | 6053 | } |
| 6057 | } | 6054 | } |
| 6058 | 6055 | ||