diff options
| author | Paul Eggert | 2013-11-04 23:11:24 -0800 |
|---|---|---|
| committer | Paul Eggert | 2013-11-04 23:11:24 -0800 |
| commit | df5b49306e8e82e2f18ed3243700c11ca7835750 (patch) | |
| tree | d98fffc7d11d4565b6132e83f54ca3f3c547b1d4 /src/alloc.c | |
| parent | 693698093480628b7438ca0fd1614b00acfd1137 (diff) | |
| download | emacs-df5b49306e8e82e2f18ed3243700c11ca7835750.tar.gz emacs-df5b49306e8e82e2f18ed3243700c11ca7835750.zip | |
Simplify and port recent bool vector changes.
* configure.ac (BITSIZEOF_SIZE_T, SIZEOF_SIZE_T):
New symbols to configure.
* src/alloc.c (ROUNDUP): Move here from lisp.h, since it's now used
only in this file. Use a more-efficient implementation if the
second argument is a power of 2.
(ALIGN): Rewrite in terms of ROUNDUP. Make it a function.
Remove no-longer-necessary compile-time checks.
(bool_vector_exact_payload_bytes): New function.
(bool_vector_payload_bytes): Remove 2nd arg; callers that need
exact payload changed to call the new function. Do not assume
that the arg or result fits in ptrdiff_t.
(bool_vector_fill): New function.
(Fmake_bool_vector): Use it. Don't assume bit counts fit
in ptrdiff_t.
(vroundup_ct): Don't assume arg fits in size_t.
* src/category.c (SET_CATEGORY_SET): Remove. All callers now just
invoke set_category_set.
(set_category_set): 2nd arg is now EMACS_INT and 3rd is now bool.
All callers changed. Use bool_vector_set.
* src/category.h (XCATEGORY_SET): Remove; no longer needed.
(CATEGORY_MEMBER): Now a function. Rewrite in terms of
bool_vector_bitref.
* src/data.c (Faref): Use bool_vector_ref.
(Faset): Use bool_vector_set.
(bits_word_to_host_endian): Don't assume you can shift by CHAR_BIT.
(Fbool_vector_not, Fbool_vector_count_matches)
(Fbool_vector_count_matches_at): Don't assume CHAR_BIT == 8.
* src/fns.c (concat): Use bool_vector_ref.
(Ffillarray): Use bool_vector_fill.
(mapcar1): Use bool_vector_ref.
(sxhash_bool_vector): Hash words, not bytes.
* src/lisp.h (BOOL_VECTOR_BITS_PER_CHAR): Now a macro as well as
a constant, since it's now used in #if.
(bits_word, BITS_WORD_MAX, BITS_PER_BITS_WORD): Fall back on
unsigned char on unusual architectures, so that we no longer
assume that the number of bits per bits_word is a power of two or
is a multiple of 8 or of CHAR_BIT.
(Qt): Add forward decl.
(struct Lisp_Bool_Vector): Don't assume EMACS_INT is aligned
at least as strictly as bits_word.
(bool_vector_data, bool_vector_uchar_data): New accessors.
All data structure accesses changed to use them.
(bool_vector_words, bool_vector_bitref, bool_vector_ref)
(bool_vector_set): New functions.
(bool_vector_fill): New decl.
(ROUNDUP): Move to alloc.c as described above.
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 108 |
1 files changed, 53 insertions, 55 deletions
diff --git a/src/alloc.c b/src/alloc.c index b35f7c4333f..7054083acba 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -361,13 +361,21 @@ static int staticidx; | |||
| 361 | 361 | ||
| 362 | static void *pure_alloc (size_t, int); | 362 | static void *pure_alloc (size_t, int); |
| 363 | 363 | ||
| 364 | /* Return X rounded to the next multiple of Y. Arguments should not | ||
| 365 | have side effects, as they are evaluated more than once. Assume X | ||
| 366 | + Y - 1 does not overflow. Tune for Y being a power of 2. */ | ||
| 364 | 367 | ||
| 365 | /* Value is SZ rounded up to the next multiple of ALIGNMENT. | 368 | #define ROUNDUP(x, y) ((y) & ((y) - 1) \ |
| 366 | ALIGNMENT must be a power of 2. */ | 369 | ? ((x) + (y) - 1) - ((x) + (y) - 1) % (y) \ |
| 370 | : ((x) + (y) - 1) & ~ ((y) - 1)) | ||
| 367 | 371 | ||
| 368 | #define ALIGN(ptr, ALIGNMENT) \ | 372 | /* Return PTR rounded up to the next multiple of ALIGNMENT. */ |
| 369 | ((void *) (((uintptr_t) (ptr) + (ALIGNMENT) - 1) \ | 373 | |
| 370 | & ~ ((ALIGNMENT) - 1))) | 374 | static void * |
| 375 | ALIGN (void *ptr, int alignment) | ||
| 376 | { | ||
| 377 | return (void *) ROUNDUP ((uintptr_t) ptr, alignment); | ||
| 378 | } | ||
| 371 | 379 | ||
| 372 | static void | 380 | static void |
| 373 | XFLOAT_INIT (Lisp_Object f, double n) | 381 | XFLOAT_INIT (Lisp_Object f, double n) |
| @@ -2026,33 +2034,39 @@ INIT must be an integer that represents a character. */) | |||
| 2026 | return val; | 2034 | return val; |
| 2027 | } | 2035 | } |
| 2028 | 2036 | ||
| 2029 | verify (sizeof (size_t) * CHAR_BIT == BITS_PER_BITS_WORD); | 2037 | static EMACS_INT |
| 2030 | verify ((BITS_PER_BITS_WORD & (BITS_PER_BITS_WORD - 1)) == 0); | 2038 | bool_vector_exact_payload_bytes (EMACS_INT nbits) |
| 2031 | |||
| 2032 | static ptrdiff_t | ||
| 2033 | bool_vector_payload_bytes (ptrdiff_t nr_bits, | ||
| 2034 | ptrdiff_t *exact_needed_bytes_out) | ||
| 2035 | { | 2039 | { |
| 2036 | ptrdiff_t exact_needed_bytes; | 2040 | eassume (0 <= nbits); |
| 2037 | ptrdiff_t needed_bytes; | 2041 | return (nbits + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR; |
| 2042 | } | ||
| 2038 | 2043 | ||
| 2039 | eassume (nr_bits >= 0); | 2044 | static EMACS_INT |
| 2045 | bool_vector_payload_bytes (EMACS_INT nbits) | ||
| 2046 | { | ||
| 2047 | EMACS_INT exact_needed_bytes = bool_vector_exact_payload_bytes (nbits); | ||
| 2040 | 2048 | ||
| 2041 | exact_needed_bytes = ROUNDUP ((size_t) nr_bits, CHAR_BIT) / CHAR_BIT; | 2049 | /* Always allocate at least one machine word of payload so that |
| 2042 | needed_bytes = ROUNDUP ((size_t) nr_bits, BITS_PER_BITS_WORD) / CHAR_BIT; | 2050 | bool-vector operations in data.c don't need a special case |
| 2051 | for empty vectors. */ | ||
| 2052 | return ROUNDUP (exact_needed_bytes + !exact_needed_bytes, | ||
| 2053 | sizeof (bits_word)); | ||
| 2054 | } | ||
| 2043 | 2055 | ||
| 2044 | if (needed_bytes == 0) | 2056 | void |
| 2057 | bool_vector_fill (Lisp_Object a, Lisp_Object init) | ||
| 2058 | { | ||
| 2059 | EMACS_INT nbits = bool_vector_size (a); | ||
| 2060 | if (0 < nbits) | ||
| 2045 | { | 2061 | { |
| 2046 | /* Always allocate at least one machine word of payload so that | 2062 | unsigned char *data = bool_vector_uchar_data (a); |
| 2047 | bool-vector operations in data.c don't need a special case | 2063 | int pattern = NILP (init) ? 0 : (1 << BOOL_VECTOR_BITS_PER_CHAR) - 1; |
| 2048 | for empty vectors. */ | 2064 | ptrdiff_t nbytes = ((nbits + BOOL_VECTOR_BITS_PER_CHAR - 1) |
| 2049 | needed_bytes = sizeof (bits_word); | 2065 | / BOOL_VECTOR_BITS_PER_CHAR); |
| 2066 | int last_mask = ~ (~0 << ((nbits - 1) % BOOL_VECTOR_BITS_PER_CHAR + 1)); | ||
| 2067 | memset (data, pattern, nbytes - 1); | ||
| 2068 | data[nbytes - 1] = pattern & last_mask; | ||
| 2050 | } | 2069 | } |
| 2051 | |||
| 2052 | if (exact_needed_bytes_out != NULL) | ||
| 2053 | *exact_needed_bytes_out = exact_needed_bytes; | ||
| 2054 | |||
| 2055 | return needed_bytes; | ||
| 2056 | } | 2070 | } |
| 2057 | 2071 | ||
| 2058 | DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, | 2072 | DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, |
| @@ -2060,42 +2074,29 @@ DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, | |||
| 2060 | LENGTH must be a number. INIT matters only in whether it is t or nil. */) | 2074 | LENGTH must be a number. INIT matters only in whether it is t or nil. */) |
| 2061 | (Lisp_Object length, Lisp_Object init) | 2075 | (Lisp_Object length, Lisp_Object init) |
| 2062 | { | 2076 | { |
| 2063 | register Lisp_Object val; | 2077 | Lisp_Object val; |
| 2064 | struct Lisp_Bool_Vector *p; | 2078 | struct Lisp_Bool_Vector *p; |
| 2065 | ptrdiff_t exact_payload_bytes; | 2079 | EMACS_INT exact_payload_bytes, total_payload_bytes, needed_elements; |
| 2066 | ptrdiff_t total_payload_bytes; | ||
| 2067 | ptrdiff_t needed_elements; | ||
| 2068 | 2080 | ||
| 2069 | CHECK_NATNUM (length); | 2081 | CHECK_NATNUM (length); |
| 2070 | if (PTRDIFF_MAX < XFASTINT (length)) | ||
| 2071 | memory_full (SIZE_MAX); | ||
| 2072 | |||
| 2073 | total_payload_bytes = bool_vector_payload_bytes | ||
| 2074 | (XFASTINT (length), &exact_payload_bytes); | ||
| 2075 | 2082 | ||
| 2076 | eassume (exact_payload_bytes <= total_payload_bytes); | 2083 | exact_payload_bytes = bool_vector_exact_payload_bytes (XFASTINT (length)); |
| 2077 | eassume (0 <= exact_payload_bytes); | 2084 | total_payload_bytes = bool_vector_payload_bytes (XFASTINT (length)); |
| 2078 | 2085 | ||
| 2079 | needed_elements = ROUNDUP ((size_t) ((bool_header_size - header_size) | 2086 | needed_elements = ((bool_header_size - header_size + total_payload_bytes |
| 2080 | + total_payload_bytes), | 2087 | + word_size - 1) |
| 2081 | word_size) / word_size; | 2088 | / word_size); |
| 2082 | 2089 | ||
| 2083 | p = (struct Lisp_Bool_Vector *) allocate_vector (needed_elements); | 2090 | p = (struct Lisp_Bool_Vector *) allocate_vector (needed_elements); |
| 2084 | XSETVECTOR (val, p); | 2091 | XSETVECTOR (val, p); |
| 2085 | XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0); | 2092 | XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0); |
| 2086 | 2093 | ||
| 2087 | p->size = XFASTINT (length); | 2094 | p->size = XFASTINT (length); |
| 2088 | if (exact_payload_bytes) | 2095 | bool_vector_fill (val, init); |
| 2089 | { | ||
| 2090 | memset (p->data, ! NILP (init) ? -1 : 0, exact_payload_bytes); | ||
| 2091 | |||
| 2092 | /* Clear any extraneous bits in the last byte. */ | ||
| 2093 | p->data[exact_payload_bytes - 1] | ||
| 2094 | &= (1 << ((XFASTINT (length) - 1) % BOOL_VECTOR_BITS_PER_CHAR + 1)) - 1; | ||
| 2095 | } | ||
| 2096 | 2096 | ||
| 2097 | /* Clear padding at the end. */ | 2097 | /* Clear padding at the end. */ |
| 2098 | memset (p->data + exact_payload_bytes, | 2098 | eassume (exact_payload_bytes <= total_payload_bytes); |
| 2099 | memset (bool_vector_uchar_data (val) + exact_payload_bytes, | ||
| 2099 | 0, | 2100 | 0, |
| 2100 | total_payload_bytes - exact_payload_bytes); | 2101 | total_payload_bytes - exact_payload_bytes); |
| 2101 | 2102 | ||
| @@ -2648,7 +2649,7 @@ verify ((VECTOR_BLOCK_SIZE % roundup_size) == 0); | |||
| 2648 | verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS)); | 2649 | verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS)); |
| 2649 | 2650 | ||
| 2650 | /* Round up X to nearest mult-of-ROUNDUP_SIZE --- use at compile time. */ | 2651 | /* Round up X to nearest mult-of-ROUNDUP_SIZE --- use at compile time. */ |
| 2651 | #define vroundup_ct(x) ROUNDUP ((size_t) (x), roundup_size) | 2652 | #define vroundup_ct(x) ROUNDUP (x, roundup_size) |
| 2652 | /* Round up X to nearest mult-of-ROUNDUP_SIZE --- use at runtime. */ | 2653 | /* Round up X to nearest mult-of-ROUNDUP_SIZE --- use at runtime. */ |
| 2653 | #define vroundup(x) (eassume ((x) >= 0), vroundup_ct (x)) | 2654 | #define vroundup(x) (eassume ((x) >= 0), vroundup_ct (x)) |
| 2654 | 2655 | ||
| @@ -2856,11 +2857,8 @@ vector_nbytes (struct Lisp_Vector *v) | |||
| 2856 | if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR)) | 2857 | if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR)) |
| 2857 | { | 2858 | { |
| 2858 | struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) v; | 2859 | struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) v; |
| 2859 | ptrdiff_t payload_bytes = | 2860 | ptrdiff_t payload_bytes = bool_vector_payload_bytes (bv->size); |
| 2860 | bool_vector_payload_bytes (bv->size, NULL); | 2861 | size = bool_header_size + payload_bytes; |
| 2861 | |||
| 2862 | eassume (payload_bytes >= 0); | ||
| 2863 | size = bool_header_size + ROUNDUP (payload_bytes, word_size); | ||
| 2864 | } | 2862 | } |
| 2865 | else | 2863 | else |
| 2866 | size = (header_size | 2864 | size = (header_size |