From 914adc427f7d1159356e465ec616c65a2ea902af Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 8 Nov 2012 18:10:28 +0400 Subject: [PATCH] Shrink struct vectorlike_header to the only size field. * lisp.h (enum pvec_type): Avoid explicit enum member values. Adjust comment. (enum More_Lisp_Bits): Change PSEUDOVECTOR_SIZE_BITS and PVEC_TYPE_MASK to arrange new bitfield in the vector header. (PSEUDOVECTOR_REST_BITS, PSEUDOVECTOR_REST_MASK): New members. (PSEUDOVECTOR_AREA_BITS): New member used to extract subtype information from the vector header. Adjust comment. (XSETPVECTYPE, XSETPVECTYPESIZE, XSETTYPED_PSEUDOVECTOR) (PSEUDOVECTOR_TYPEP, DEFUN): Adjust to match new vector header layout. (XSETSUBR, SUBRP): Adjust to match new Lisp_Subr layout. (struct vectorlike_header): Remove next member. Adjust comment. (struct Lisp_Subr): Add convenient header. Adjust comment. (allocate_pseudovector): Adjust prototype. * alloc.c (mark_glyph_matrix, mark_face_cache, allocate_string) (sweep_string, lisp_malloc): Remove useless prototypes. (enum mem_type): Adjust comment. (NEXT_IN_FREE_LIST): New macro. (SETUP_ON_FREE_LIST): Adjust XSETPVECTYPESIZE usage. (Fmake_bool_vector): Likewise. (struct large_vector): New type to represent allocation unit for the vectors with the memory footprint more than VBLOOCK_BYTES_MAX. (large_vectors): Change type to struct large_vector. (allocate_vector_from_block): Simplify. (PSEUDOVECTOR_NBYTES): Replace with... (vector_nbytes): ...new function. Adjust users. (sweep_vectors): Adjust processing of large vectors. (allocate_vectorlike): Likewise. (allocate_pseudovector): Change type of 3rd arg to enum pvec_type. Add easserts. Adjust XSETPVECTYPESIZE usage. (allocate_buffer): Use BUFFER_PVEC_INIT. (live_vector_p): Adjust to match large vector. * buffer.c (init_buffer_once): Use BUFFER_PVEC_INIT. * buffer.h (struct buffer): Add next member. (BUFFER_LISP_SIZE, BUFFER_REST_SIZE, BUFFER_PVEC_INIT): New macros. (FOR_EACH_BUFFER): Adjust to match struct buffer change. * fns.c (internal_equal): Adjust to match enum pvec_type change. (copy_hash_table): Adjust to match vector header change. * lread.c (defsubr): Use XSETPVECTYPE. * .gdbinit (xpr, xbacktrace): Adjust to match vector header change. (xvectype): Likewise. Print PVEC_NORMAL_VECTOR for regular vectors. (xvecsize): New command. --- src/.gdbinit | 25 +++++-- src/ChangeLog | 47 +++++++++++++ src/alloc.c | 185 +++++++++++++++++++++++++++++++------------------- src/buffer.c | 9 +-- src/buffer.h | 31 +++++++-- src/fns.c | 8 +-- src/lisp.h | 114 +++++++++++++------------------ src/lread.c | 2 +- 8 files changed, 260 insertions(+), 161 deletions(-) diff --git a/src/.gdbinit b/src/.gdbinit index 952d7392a4..f187bafcba 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -654,13 +654,30 @@ define xvectype xgetptr $ set $size = ((struct Lisp_Vector *) $ptr)->header.size if ($size & PSEUDOVECTOR_FLAG) - output (enum pvec_type) (($size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_SIZE_BITS) + output (enum pvec_type) (($size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS) else - output $size & ~ARRAY_MARK_FLAG + output PVEC_NORMAL_VECTOR end echo \n end document xvectype +Print the type or vector subtype of $. +This command assumes that $ is a vector or pseudovector. +end + +define xvecsize + xgetptr $ + set $size = ((struct Lisp_Vector *) $ptr)->header.size + if ($size & PSEUDOVECTOR_FLAG) + output ($size & PSEUDOVECTOR_SIZE_MASK) + echo \n + output (($size & PSEUDOVECTOR_REST_MASK) >> PSEUDOVECTOR_SIZE_BITS) + else + output ($size & ~ARRAY_MARK_FLAG) + end + echo \n +end +document xvecsize Print the size or vector subtype of $. This command assumes that $ is a vector or pseudovector. end @@ -996,7 +1013,7 @@ define xpr if $type == Lisp_Vectorlike set $size = ((struct Lisp_Vector *) $ptr)->header.size if ($size & PSEUDOVECTOR_FLAG) - set $vec = (enum pvec_type) (($size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_SIZE_BITS) + set $vec = (enum pvec_type) (($size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS) if $vec == PVEC_NORMAL_VECTOR xvector end @@ -1132,7 +1149,7 @@ define xbacktrace xgetptr ($bt->function) set $size = ((struct Lisp_Vector *) $ptr)->header.size if ($size & PSEUDOVECTOR_FLAG) - output (enum pvec_type) (($size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_SIZE_BITS) + output (enum pvec_type) (($size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS) else output $size & ~ARRAY_MARK_FLAG end diff --git a/src/ChangeLog b/src/ChangeLog index 291eec18fe..7ddff43d94 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,50 @@ +2012-11-08 Dmitry Antipov + + Shrink struct vectorlike_header to the only size field. + * lisp.h (enum pvec_type): Avoid explicit enum member values. + Adjust comment. + (enum More_Lisp_Bits): Change PSEUDOVECTOR_SIZE_BITS and + PVEC_TYPE_MASK to arrange new bitfield in the vector header. + (PSEUDOVECTOR_REST_BITS, PSEUDOVECTOR_REST_MASK): New members. + (PSEUDOVECTOR_AREA_BITS): New member used to extract subtype + information from the vector header. Adjust comment. + (XSETPVECTYPE, XSETPVECTYPESIZE, XSETTYPED_PSEUDOVECTOR) + (PSEUDOVECTOR_TYPEP, DEFUN): Adjust to match new vector header + layout. + (XSETSUBR, SUBRP): Adjust to match new Lisp_Subr layout. + (struct vectorlike_header): Remove next member. Adjust comment. + (struct Lisp_Subr): Add convenient header. Adjust comment. + (allocate_pseudovector): Adjust prototype. + * alloc.c (mark_glyph_matrix, mark_face_cache, allocate_string) + (sweep_string, lisp_malloc): Remove useless prototypes. + (enum mem_type): Adjust comment. + (NEXT_IN_FREE_LIST): New macro. + (SETUP_ON_FREE_LIST): Adjust XSETPVECTYPESIZE usage. + (Fmake_bool_vector): Likewise. + (struct large_vector): New type to represent allocation unit for + the vectors with the memory footprint more than VBLOOCK_BYTES_MAX. + (large_vectors): Change type to struct large_vector. + (allocate_vector_from_block): Simplify. + (PSEUDOVECTOR_NBYTES): Replace with... + (vector_nbytes): ...new function. Adjust users. + (sweep_vectors): Adjust processing of large vectors. + (allocate_vectorlike): Likewise. + (allocate_pseudovector): Change type of 3rd arg to enum pvec_type. + Add easserts. Adjust XSETPVECTYPESIZE usage. + (allocate_buffer): Use BUFFER_PVEC_INIT. + (live_vector_p): Adjust to match large vector. + * buffer.c (init_buffer_once): Use BUFFER_PVEC_INIT. + * buffer.h (struct buffer): Add next member. + (BUFFER_LISP_SIZE, BUFFER_REST_SIZE, BUFFER_PVEC_INIT): + New macros. + (FOR_EACH_BUFFER): Adjust to match struct buffer change. + * fns.c (internal_equal): Adjust to match enum pvec_type change. + (copy_hash_table): Adjust to match vector header change. + * lread.c (defsubr): Use XSETPVECTYPE. + * .gdbinit (xpr, xbacktrace): Adjust to match vector header change. + (xvectype): Likewise. Print PVEC_NORMAL_VECTOR for regular vectors. + (xvecsize): New command. + 2012-11-08 Dmitry Antipov * keyboard.c (event_to_kboard): Do not dereference diff --git a/src/alloc.c b/src/alloc.c index 5bb528c64a..557c68ca5a 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -216,23 +216,19 @@ static Lisp_Object Qpost_gc_hook; static void mark_terminals (void); static void gc_sweep (void); static Lisp_Object make_pure_vector (ptrdiff_t); -static void mark_glyph_matrix (struct glyph_matrix *); -static void mark_face_cache (struct face_cache *); static void mark_buffer (struct buffer *); #if !defined REL_ALLOC || defined SYSTEM_MALLOC static void refill_memory_reserve (void); #endif -static struct Lisp_String *allocate_string (void); static void compact_small_strings (void); static void free_large_strings (void); -static void sweep_strings (void); static void free_misc (Lisp_Object); extern Lisp_Object which_symbols (Lisp_Object, EMACS_INT) EXTERNALLY_VISIBLE; -/* When scanning the C stack for live Lisp objects, Emacs keeps track - of what memory allocated via lisp_malloc is intended for what - purpose. This enumeration specifies the type of memory. */ +/* When scanning the C stack for live Lisp objects, Emacs keeps track of + what memory allocated via lisp_malloc and lisp_align_malloc is intended + for what purpose. This enumeration specifies the type of memory. */ enum mem_type { @@ -243,10 +239,9 @@ enum mem_type MEM_TYPE_MISC, MEM_TYPE_SYMBOL, MEM_TYPE_FLOAT, - /* We used to keep separate mem_types for subtypes of vectors such as - process, hash_table, frame, terminal, and window, but we never made - use of the distinction, so it only caused source-code complexity - and runtime slowdown. Minor but pointless. */ + /* Since all non-bool pseudovectors are small enough to be + allocated from vector blocks, this memory type denotes + large regular vectors and large bool pseudovectors. */ MEM_TYPE_VECTORLIKE, /* Special type to denote vector blocks. */ MEM_TYPE_VECTOR_BLOCK, @@ -254,9 +249,6 @@ enum mem_type MEM_TYPE_SPARE }; -static void *lisp_malloc (size_t, enum mem_type); - - #if GC_MARK_STACK || defined GC_MALLOC_CHECK #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES @@ -2040,7 +2032,7 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) val = Fmake_vector (make_number (length_in_elts + extra_bool_elts), Qnil); /* No Lisp_Object to trace in there. */ - XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0); + XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0); p = XBOOL_VECTOR (val); p->size = XFASTINT (length); @@ -2619,19 +2611,49 @@ verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS)); #define VINDEX(nbytes) (((nbytes) - VBLOCK_BYTES_MIN) / roundup_size) +/* When V is on the free list, first word after header is used as a pointer + to next vector on the free list. It might be done in a better way with: + + (*(struct Lisp_Vector **)&(v->contents[0])) + + but this breaks GCC's strict-aliasing rules (which looks more relaxed + for char and void pointers). */ + +#define NEXT_IN_FREE_LIST(v) \ + (*(struct Lisp_Vector **)((char *) v + header_size)) + /* Common shortcut to setup vector on a free list. */ -#define SETUP_ON_FREE_LIST(v, nbytes, index) \ - do { \ - XSETPVECTYPESIZE (v, PVEC_FREE, nbytes); \ - eassert ((nbytes) % roundup_size == 0); \ - (index) = VINDEX (nbytes); \ - eassert ((index) < VECTOR_MAX_FREE_LIST_INDEX); \ - (v)->header.next.vector = vector_free_lists[index]; \ - vector_free_lists[index] = (v); \ - total_free_vector_slots += (nbytes) / word_size; \ +#define SETUP_ON_FREE_LIST(v, nbytes, tmp) \ + do { \ + (tmp) = ((nbytes - header_size) / word_size); \ + XSETPVECTYPESIZE (v, PVEC_FREE, 0, (tmp)); \ + eassert ((nbytes) % roundup_size == 0); \ + (tmp) = VINDEX (nbytes); \ + eassert ((tmp) < VECTOR_MAX_FREE_LIST_INDEX); \ + NEXT_IN_FREE_LIST (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. */ + +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 (sizeof (struct large_vector *))]; +#endif + } next; + struct Lisp_Vector v; +}; + +/* This internal type is used to maintain an underlying storage + for small vectors. */ + struct vector_block { char data[VECTOR_BLOCK_BYTES]; @@ -2649,7 +2671,7 @@ static struct Lisp_Vector *vector_free_lists[VECTOR_MAX_FREE_LIST_INDEX]; /* Singly-linked list of large vectors. */ -static struct Lisp_Vector *large_vectors; +static struct large_vector *large_vectors; /* The only vector with 0 slots, allocated from pure space. */ @@ -2693,7 +2715,7 @@ init_vectors (void) static struct Lisp_Vector * allocate_vector_from_block (size_t nbytes) { - struct Lisp_Vector *vector, *rest; + struct Lisp_Vector *vector; struct vector_block *block; size_t index, restbytes; @@ -2706,8 +2728,7 @@ allocate_vector_from_block (size_t nbytes) if (vector_free_lists[index]) { vector = vector_free_lists[index]; - vector_free_lists[index] = vector->header.next.vector; - vector->header.next.nbytes = nbytes; + vector_free_lists[index] = NEXT_IN_FREE_LIST (vector); total_free_vector_slots -= nbytes / word_size; return vector; } @@ -2721,16 +2742,14 @@ allocate_vector_from_block (size_t nbytes) { /* This vector is larger than requested. */ vector = vector_free_lists[index]; - vector_free_lists[index] = vector->header.next.vector; - vector->header.next.nbytes = nbytes; + vector_free_lists[index] = NEXT_IN_FREE_LIST (vector); total_free_vector_slots -= nbytes / word_size; /* Excess bytes are used for the smaller vector, which should be set on an appropriate free list. */ restbytes = index * roundup_size + VBLOCK_BYTES_MIN - nbytes; eassert (restbytes % roundup_size == 0); - rest = ADVANCE (vector, nbytes); - SETUP_ON_FREE_LIST (rest, restbytes, index); + SETUP_ON_FREE_LIST (ADVANCE (vector, nbytes), restbytes, index); return vector; } @@ -2739,7 +2758,6 @@ allocate_vector_from_block (size_t nbytes) /* New vector will be at the beginning of this block. */ vector = (struct Lisp_Vector *) block->data; - vector->header.next.nbytes = nbytes; /* If the rest of space from this block is large enough for one-slot vector at least, set up it on a free list. */ @@ -2747,11 +2765,10 @@ allocate_vector_from_block (size_t nbytes) if (restbytes >= VBLOCK_BYTES_MIN) { eassert (restbytes % roundup_size == 0); - rest = ADVANCE (vector, nbytes); - SETUP_ON_FREE_LIST (rest, restbytes, index); + SETUP_ON_FREE_LIST (ADVANCE (vector, nbytes), restbytes, index); } return vector; - } +} /* Nonzero if VECTOR pointer is valid pointer inside BLOCK. */ @@ -2759,15 +2776,30 @@ allocate_vector_from_block (size_t nbytes) ((char *) (vector) <= (block)->data \ + VECTOR_BLOCK_BYTES - VBLOCK_BYTES_MIN) -/* Number of bytes used by vector-block-allocated object. This is the only - place where we actually use the `nbytes' field of the vector-header. - I.e. we could get rid of the `nbytes' field by computing it based on the - vector-type. */ +/* Return the memory footprint of V in bytes. */ -#define PSEUDOVECTOR_NBYTES(vector) \ - (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_FREE) \ - ? vector->header.size & PSEUDOVECTOR_SIZE_MASK \ - : vector->header.next.nbytes) +static ptrdiff_t +vector_nbytes (struct Lisp_Vector *v) +{ + ptrdiff_t size = v->header.size & ~ARRAY_MARK_FLAG; + + if (size & PSEUDOVECTOR_FLAG) + { + if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR)) + size = (bool_header_size + + (((struct Lisp_Bool_Vector *) v)->size + + BOOL_VECTOR_BITS_PER_CHAR - 1) + / BOOL_VECTOR_BITS_PER_CHAR); + else + size = (header_size + + ((size & PSEUDOVECTOR_SIZE_MASK) + + ((size & PSEUDOVECTOR_REST_MASK) + >> PSEUDOVECTOR_SIZE_BITS)) * word_size); + } + else + size = header_size + size * word_size; + return vroundup (size); +} /* Reclaim space used by unmarked vectors. */ @@ -2775,7 +2807,8 @@ static void sweep_vectors (void) { struct vector_block *block = vector_blocks, **bprev = &vector_blocks; - struct Lisp_Vector *vector, *next, **vprev = &large_vectors; + struct large_vector *lv, **lvprev = &large_vectors; + struct Lisp_Vector *vector, *next; total_vectors = total_vector_slots = total_free_vector_slots = 0; memset (vector_free_lists, 0, sizeof (vector_free_lists)); @@ -2785,6 +2818,7 @@ sweep_vectors (void) for (block = vector_blocks; block; block = *bprev) { bool free_this_block = 0; + ptrdiff_t nbytes; for (vector = (struct Lisp_Vector *) block->data; VECTOR_IN_BLOCK (vector, block); vector = next) @@ -2793,14 +2827,16 @@ sweep_vectors (void) { VECTOR_UNMARK (vector); total_vectors++; - total_vector_slots += vector->header.next.nbytes / word_size; - next = ADVANCE (vector, vector->header.next.nbytes); + nbytes = vector_nbytes (vector); + total_vector_slots += nbytes / word_size; + next = ADVANCE (vector, nbytes); } else { - ptrdiff_t nbytes = PSEUDOVECTOR_NBYTES (vector); - ptrdiff_t total_bytes = nbytes; + ptrdiff_t total_bytes; + nbytes = vector_nbytes (vector); + total_bytes = nbytes; next = ADVANCE (vector, nbytes); /* While NEXT is not marked, try to coalesce with VECTOR, @@ -2810,7 +2846,7 @@ sweep_vectors (void) { if (VECTOR_MARKED_P (next)) break; - nbytes = PSEUDOVECTOR_NBYTES (next); + nbytes = vector_nbytes (next); total_bytes += nbytes; next = ADVANCE (next, nbytes); } @@ -2844,8 +2880,9 @@ sweep_vectors (void) /* Sweep large vectors. */ - for (vector = large_vectors; vector; vector = *vprev) + for (lv = large_vectors; lv; lv = *lvprev) { + vector = &lv->v; if (VECTOR_MARKED_P (vector)) { VECTOR_UNMARK (vector); @@ -2867,12 +2904,12 @@ sweep_vectors (void) else total_vector_slots += header_size / word_size + vector->header.size; - vprev = &vector->header.next.vector; + lvprev = &lv->next.vector; } else { - *vprev = vector->header.next.vector; - lisp_free (vector); + *lvprev = lv->next.vector; + lisp_free (lv); } } } @@ -2904,9 +2941,12 @@ allocate_vectorlike (ptrdiff_t len) p = allocate_vector_from_block (vroundup (nbytes)); else { - p = lisp_malloc (nbytes, MEM_TYPE_VECTORLIKE); - p->header.next.vector = large_vectors; - large_vectors = p; + struct large_vector *lv + = lisp_malloc (sizeof (*lv) + (len - 1) * word_size, + MEM_TYPE_VECTORLIKE); + lv->next.vector = large_vectors; + large_vectors = lv; + p = &lv->v; } #ifdef DOUG_LEA_MALLOC @@ -2943,16 +2983,21 @@ allocate_vector (EMACS_INT len) /* Allocate other vector-like structures. */ struct Lisp_Vector * -allocate_pseudovector (int memlen, int lisplen, int tag) +allocate_pseudovector (int memlen, int lisplen, enum pvec_type tag) { struct Lisp_Vector *v = allocate_vectorlike (memlen); int i; + /* Catch bogus values. */ + eassert (tag <= PVEC_FONT); + eassert (memlen - lisplen <= (1 << PSEUDOVECTOR_REST_BITS) - 1); + eassert (lisplen <= (1 << PSEUDOVECTOR_SIZE_BITS) - 1); + /* Only the first lisplen slots will be traced normally by the GC. */ for (i = 0; i < lisplen; ++i) v->contents[i] = Qnil; - XSETPVECTYPESIZE (v, tag, lisplen); + XSETPVECTYPESIZE (v, tag, lisplen, memlen - lisplen); return v; } @@ -2961,10 +3006,9 @@ allocate_buffer (void) { struct buffer *b = lisp_malloc (sizeof *b, MEM_TYPE_BUFFER); - XSETPVECTYPESIZE (b, PVEC_BUFFER, (offsetof (struct buffer, own_text) - - header_size) / word_size); + BUFFER_PVEC_INIT (b); /* Put B on the chain of all buffers including killed ones. */ - b->header.next.buffer = all_buffers; + b->next = all_buffers; all_buffers = b; /* Note that the rest fields of B are not initialized. */ return b; @@ -4068,16 +4112,15 @@ live_vector_p (struct mem_node *m, void *p) while (VECTOR_IN_BLOCK (vector, block) && vector <= (struct Lisp_Vector *) p) { - if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_FREE)) - vector = ADVANCE (vector, (vector->header.size - & PSEUDOVECTOR_SIZE_MASK)); - else if (vector == p) + if (!PSEUDOVECTOR_TYPEP (&vector->header, PVEC_FREE) && vector == p) return 1; else - vector = ADVANCE (vector, vector->header.next.nbytes); + vector = ADVANCE (vector, vector_nbytes (vector)); } } - else if (m->type == MEM_TYPE_VECTORLIKE && p == m->start) + else if (m->type == MEM_TYPE_VECTORLIKE + && (char *) p == ((char *) m->start + + offsetof (struct large_vector, v))) /* This memory node corresponds to a large vector. */ return 1; return 0; @@ -5687,7 +5730,7 @@ mark_object (Lisp_Object arg) if (ptr->header.size & PSEUDOVECTOR_FLAG) pvectype = ((ptr->header.size & PVEC_TYPE_MASK) - >> PSEUDOVECTOR_SIZE_BITS); + >> PSEUDOVECTOR_AREA_BITS); else pvectype = PVEC_NORMAL_VECTOR; @@ -6317,7 +6360,7 @@ gc_sweep (void) for (buffer = all_buffers; buffer; buffer = *bprev) if (!VECTOR_MARKED_P (buffer)) { - *bprev = buffer->header.next.buffer; + *bprev = buffer->next; lisp_free (buffer); } else @@ -6326,7 +6369,7 @@ gc_sweep (void) /* Do not use buffer_(set|get)_intervals here. */ buffer->text->intervals = balance_intervals (buffer->text->intervals); total_buffers++; - bprev = &buffer->header.next.buffer; + bprev = &buffer->next; } } diff --git a/src/buffer.c b/src/buffer.c index bb69675346..1d58df54f6 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -5105,11 +5105,6 @@ void init_buffer_once (void) { int idx; - /* If you add, remove, or reorder Lisp_Objects in a struct buffer, make - sure that this is still correct. Otherwise, mark_vectorlike may not - trace all Lisp_Objects in buffer_defaults and buffer_local_symbols. */ - const int pvecsize - = (offsetof (struct buffer, own_text) - header_size) / word_size; memset (buffer_permanent_local_flags, 0, sizeof buffer_permanent_local_flags); @@ -5132,8 +5127,8 @@ init_buffer_once (void) /* This is not strictly necessary, but let's make them initialized. */ bset_name (&buffer_defaults, build_pure_c_string (" *buffer-defaults*")); bset_name (&buffer_local_symbols, build_pure_c_string (" *buffer-local-symbols*")); - XSETPVECTYPESIZE (&buffer_defaults, PVEC_BUFFER, pvecsize); - XSETPVECTYPESIZE (&buffer_local_symbols, PVEC_BUFFER, pvecsize); + BUFFER_PVEC_INIT (&buffer_defaults); + BUFFER_PVEC_INIT (&buffer_local_symbols); /* Set up the default values of various buffer slots. */ /* Must do these before making the first buffer! */ diff --git a/src/buffer.h b/src/buffer.h index 9e0e9eef0b..fbbbf1b843 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -482,11 +482,6 @@ struct buffer_text struct buffer { - /* HEADER.NEXT is the next buffer, in chain of all buffers, including killed - buffers. This chain, starting from all_buffers, is used only for garbage - collection, in order to collect killed buffers properly. Note that large - vectors and large pseudo-vector objects are all on another chain starting - from large_vectors. */ struct vectorlike_header header; /* The name of this buffer. */ @@ -750,6 +745,9 @@ struct buffer In an indirect buffer, this is the own_text field of another buffer. */ struct buffer_text *text; + /* Next buffer, in chain of all buffers, including killed ones. */ + struct buffer *next; + /* Char position of point in buffer. */ ptrdiff_t pt; @@ -959,6 +957,27 @@ bset_width_table (struct buffer *b, Lisp_Object val) b->INTERNAL_FIELD (width_table) = val; } +/* Number of Lisp_Objects at the beginning of struct buffer. + If you add, remove, or reorder Lisp_Objects within buffer + structure, make sure that this is still correct. */ + +#define BUFFER_LISP_SIZE \ + ((offsetof (struct buffer, own_text) - header_size) / word_size) + +/* Size of the struct buffer part beyond leading Lisp_Objects, in word_size + units. Rounding is needed for --with-wide-int configuration. */ + +#define BUFFER_REST_SIZE \ + ((((sizeof (struct buffer) - offsetof (struct buffer, own_text)) \ + + (word_size - 1)) & ~(word_size - 1)) / word_size) + +/* Initialize the pseudovector header of buffer object. BUFFER_LISP_SIZE + is required for GC, but BUFFER_REST_SIZE is set up just to be consistent + with other pseudovectors. */ + +#define BUFFER_PVEC_INIT(b) \ + XSETPVECTYPESIZE (b, PVEC_BUFFER, BUFFER_LISP_SIZE, BUFFER_REST_SIZE) + /* Convenient check whether buffer B is live. */ #define BUFFER_LIVE_P(b) (!NILP (BVAR (b, name))) @@ -986,7 +1005,7 @@ extern struct buffer *all_buffers; /* Used to iterate over the chain above. */ #define FOR_EACH_BUFFER(b) \ - for ((b) = all_buffers; (b); (b) = (b)->header.next.buffer) + for ((b) = all_buffers; (b); (b) = (b)->next) /* This points to the current buffer. */ diff --git a/src/fns.c b/src/fns.c index b1ba5ce950..1d2e510b7e 100644 --- a/src/fns.c +++ b/src/fns.c @@ -2076,9 +2076,8 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props) are sensible to compare, so eliminate the others now. */ if (size & PSEUDOVECTOR_FLAG) { - if (!(size & ((PVEC_COMPILED | PVEC_CHAR_TABLE - | PVEC_SUB_CHAR_TABLE | PVEC_FONT) - << PSEUDOVECTOR_SIZE_BITS))) + if (((size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS) + < PVEC_COMPILED) return 0; size &= PSEUDOVECTOR_SIZE_MASK; } @@ -3661,12 +3660,9 @@ copy_hash_table (struct Lisp_Hash_Table *h1) { Lisp_Object table; struct Lisp_Hash_Table *h2; - struct Lisp_Vector *next; h2 = allocate_hash_table (); - next = h2->header.next.vector; *h2 = *h1; - h2->header.next.vector = next; h2->key_and_value = Fcopy_sequence (h1->key_and_value); h2->hash = Fcopy_sequence (h1->hash); h2->next = Fcopy_sequence (h1->next); diff --git a/src/lisp.h b/src/lisp.h index 88d9b766f3..66612e2987 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -408,14 +408,11 @@ enum pvec_type PVEC_WINDOW_CONFIGURATION, PVEC_SUBR, PVEC_OTHER, - /* These last 4 are special because we OR them in fns.c:internal_equal, - so they have to use a disjoint bit pattern: - if (!(size & (PVEC_COMPILED | PVEC_CHAR_TABLE - | PVEC_SUB_CHAR_TABLE | PVEC_FONT))) */ - PVEC_COMPILED = 0x10, - PVEC_CHAR_TABLE = 0x20, - PVEC_SUB_CHAR_TABLE = 0x30, - PVEC_FONT = 0x40 + /* These should be last, check internal_equal to see why. */ + PVEC_COMPILED, + PVEC_CHAR_TABLE, + PVEC_SUB_CHAR_TABLE, + PVEC_FONT /* Should be last because it's used for range checking. */ }; /* DATA_SEG_BITS forces extra bits to be or'd in with any pointers @@ -435,9 +432,18 @@ enum More_Lisp_Bits only the number of Lisp_Object fields (that need to be traced by GC). The distinction is used, e.g., by Lisp_Process, which places extra non-Lisp_Object fields at the end of the structure. */ - PSEUDOVECTOR_SIZE_BITS = 16, + PSEUDOVECTOR_SIZE_BITS = 12, PSEUDOVECTOR_SIZE_MASK = (1 << PSEUDOVECTOR_SIZE_BITS) - 1, - PVEC_TYPE_MASK = 0x0fff << PSEUDOVECTOR_SIZE_BITS, + + /* To calculate the memory footprint of the pseudovector, it's useful + to store the size of non-Lisp area in word_size units here. */ + PSEUDOVECTOR_REST_BITS = 12, + PSEUDOVECTOR_REST_MASK = (((1 << PSEUDOVECTOR_REST_BITS) - 1) + << PSEUDOVECTOR_SIZE_BITS), + + /* Used to extract pseudovector subtype information. */ + PSEUDOVECTOR_AREA_BITS = PSEUDOVECTOR_SIZE_BITS + PSEUDOVECTOR_REST_BITS, + PVEC_TYPE_MASK = 0x3f << PSEUDOVECTOR_AREA_BITS, /* Number of bits to put in each character in the internal representation of bool vectors. This should not vary across implementations. */ @@ -608,13 +614,13 @@ clip_to_bounds (ptrdiff_t lower, EMACS_INT num, ptrdiff_t upper) /* Pseudovector types. */ -#define XSETPVECTYPE(v, code) XSETTYPED_PVECTYPE (v, header.size, code) -#define XSETTYPED_PVECTYPE(v, size_member, code) \ - ((v)->size_member |= PSEUDOVECTOR_FLAG | ((code) << PSEUDOVECTOR_SIZE_BITS)) -#define XSETPVECTYPESIZE(v, code, sizeval) \ +#define XSETPVECTYPE(v, code) \ + ((v)->header.size |= PSEUDOVECTOR_FLAG | ((code) << PSEUDOVECTOR_AREA_BITS)) +#define XSETPVECTYPESIZE(v, code, lispsize, restsize) \ ((v)->header.size = (PSEUDOVECTOR_FLAG \ - | ((code) << PSEUDOVECTOR_SIZE_BITS) \ - | (sizeval))) + | ((code) << PSEUDOVECTOR_AREA_BITS) \ + | ((restsize) << PSEUDOVECTOR_SIZE_BITS) \ + | (lispsize))) /* The cast to struct vectorlike_header * avoids aliasing issues. */ #define XSETPSEUDOVECTOR(a, b, code) \ @@ -626,16 +632,14 @@ clip_to_bounds (ptrdiff_t lower, EMACS_INT num, ptrdiff_t upper) #define XSETTYPED_PSEUDOVECTOR(a, b, size, code) \ (XSETVECTOR (a, b), \ eassert ((size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK)) \ - == (PSEUDOVECTOR_FLAG | (code << PSEUDOVECTOR_SIZE_BITS)))) + == (PSEUDOVECTOR_FLAG | (code << PSEUDOVECTOR_AREA_BITS)))) #define XSETWINDOW_CONFIGURATION(a, b) \ (XSETPSEUDOVECTOR (a, b, PVEC_WINDOW_CONFIGURATION)) #define XSETPROCESS(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_PROCESS)) #define XSETWINDOW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_WINDOW)) #define XSETTERMINAL(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_TERMINAL)) -/* XSETSUBR is special since Lisp_Subr lacks struct vectorlike_header. */ -#define XSETSUBR(a, b) \ - XSETTYPED_PSEUDOVECTOR (a, b, XSUBR (a)->size, PVEC_SUBR) +#define XSETSUBR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUBR)) #define XSETCOMPILED(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_COMPILED)) #define XSETBUFFER(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BUFFER)) #define XSETCHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_CHAR_TABLE)) @@ -802,7 +806,7 @@ struct Lisp_String }; /* Header of vector-like objects. This documents the layout constraints on - vectors and pseudovectors other than struct Lisp_Subr. It also prevents + vectors and pseudovectors (objects of PVEC_xxx subtype). It also prevents compilers from being fooled by Emacs's type punning: the XSETPSEUDOVECTOR and PSEUDOVECTORP macros cast their pointers to struct vectorlike_header *, because when two such pointers potentially alias, a compiler won't @@ -810,43 +814,26 @@ struct Lisp_String . */ struct vectorlike_header { - /* This field contains various pieces of information: + /* The only field contains various pieces of information: - The MSB (ARRAY_MARK_FLAG) holds the gcmarkbit. - The next bit (PSEUDOVECTOR_FLAG) indicates whether this is a plain vector (0) or a pseudovector (1). - If PSEUDOVECTOR_FLAG is 0, the rest holds the size (number of slots) of the vector. - - If PSEUDOVECTOR_FLAG is 1, the rest is subdivided into - a "pvec type" tag held in PVEC_TYPE_MASK and a size held in the lowest - PSEUDOVECTOR_SIZE_BITS. That size normally indicates the number of - Lisp_Object slots at the beginning of the object that need to be - traced by the GC, tho some types use it slightly differently. - - E.g. if the pvec type is PVEC_FREE it means this is an unallocated - vector on a free-list and PSEUDOVECTOR_SIZE_BITS indicates its size - in bytes. */ + - If PSEUDOVECTOR_FLAG is 1, the rest is subdivided into three fields: + - a) pseudovector subtype held in PVEC_TYPE_MASK field; + - b) number of Lisp_Objects slots at the beginning of the object + held in PSEUDOVECTOR_SIZE_MASK field. These objects are always + traced by the GC; + - c) size of the rest fields held in PSEUDOVECTOR_REST_MASK and + measured in word_size units. Rest fields may also include + Lisp_Objects, but these objects usually needs some special treatment + during GC. + There are some exceptions. For PVEC_FREE, b) is always zero. For + PVEC_BOOL_VECTOR and PVEC_SUBR, both b) and c) are always zero. + Current layout limits the pseudovectors to 63 PVEC_xxx subtypes, + 4095 Lisp_Objects in GC-ed area and 4095 word-sized other slots. */ ptrdiff_t size; - - /* When the vector is allocated from a vector block, NBYTES is used - if the vector is not on a free list, and VECTOR is used otherwise. - For large vector-like objects, BUFFER or VECTOR is used as a pointer - to the next vector-like object. It is generally a buffer or a - Lisp_Vector alias, so for convenience it is a union instead of a - pointer: this way, one can write P->next.vector instead of ((struct - Lisp_Vector *) P->next). */ - union { - /* This is only needed for small vectors that are not free because the - `size' field only gives us the number of Lisp_Object slots, whereas we - need to know the total size, including non-Lisp_Object data. - FIXME: figure out a way to store this info elsewhere so we can - finally get rid of this extra word of overhead. */ - ptrdiff_t nbytes; - struct buffer *buffer; - /* FIXME: This can be removed: For large vectors, this field could be - placed *before* the vector itself. And for small vectors on a free - list, this field could be stored in the vector's bytes, since the - empty vector is handled specially anyway. */ - struct Lisp_Vector *vector; - } next; }; /* Regular vector is just a header plus array of Lisp_Objects. */ @@ -1020,15 +1007,11 @@ struct Lisp_Sub_Char_Table /* This structure describes a built-in function. It is generated by the DEFUN macro only. - defsubr makes it into a Lisp object. - - This type is treated in most respects as a pseudovector, - but since we never dynamically allocate or free them, - we don't need a struct vectorlike_header and its 'next' field. */ + defsubr makes it into a Lisp object. */ struct Lisp_Subr { - ptrdiff_t size; + struct vectorlike_header header; union { Lisp_Object (*a0) (void); Lisp_Object (*a1) (Lisp_Object); @@ -1709,7 +1692,7 @@ typedef struct { #define PSEUDOVECTOR_TYPEP(v, code) \ (((v)->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK)) \ - == (PSEUDOVECTOR_FLAG | ((code) << PSEUDOVECTOR_SIZE_BITS))) + == (PSEUDOVECTOR_FLAG | ((code) << PSEUDOVECTOR_AREA_BITS))) /* True if object X, with internal type struct T *, is a pseudovector whose code is CODE. */ @@ -1722,8 +1705,7 @@ typedef struct { #define PROCESSP(x) PSEUDOVECTORP (x, PVEC_PROCESS) #define WINDOWP(x) PSEUDOVECTORP (x, PVEC_WINDOW) #define TERMINALP(x) PSEUDOVECTORP (x, PVEC_TERMINAL) -/* SUBRP is special since Lisp_Subr lacks struct vectorlike_header. */ -#define SUBRP(x) TYPED_PSEUDOVECTORP (x, Lisp_Subr, PVEC_SUBR) +#define SUBRP(x) PSEUDOVECTORP (x, PVEC_SUBR) #define COMPILEDP(x) PSEUDOVECTORP (x, PVEC_COMPILED) #define BUFFERP(x) PSEUDOVECTORP (x, PVEC_BUFFER) #define CHAR_TABLE_P(x) PSEUDOVECTORP (x, PVEC_CHAR_TABLE) @@ -1898,8 +1880,8 @@ typedef struct { #define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc) \ Lisp_Object fnname DEFUN_ARGS_ ## maxargs ; \ static struct Lisp_Subr alignas (GCALIGNMENT) sname = \ - { (PVEC_SUBR << PSEUDOVECTOR_SIZE_BITS) \ - | (sizeof (struct Lisp_Subr) / sizeof (EMACS_INT)), \ + { { (PVEC_SUBR << PSEUDOVECTOR_AREA_BITS) \ + | (sizeof (struct Lisp_Subr) / sizeof (EMACS_INT)) }, \ { (Lisp_Object (__cdecl *)(void))fnname }, \ minargs, maxargs, lname, intspec, 0}; \ Lisp_Object fnname @@ -1907,8 +1889,8 @@ typedef struct { #define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc) \ Lisp_Object fnname DEFUN_ARGS_ ## maxargs ; \ static struct Lisp_Subr alignas (GCALIGNMENT) sname = \ - { PVEC_SUBR << PSEUDOVECTOR_SIZE_BITS, \ - { .a ## maxargs = fnname }, \ + { { PVEC_SUBR << PSEUDOVECTOR_AREA_BITS }, \ + { .a ## maxargs = fnname }, \ minargs, maxargs, lname, intspec, 0}; \ Lisp_Object fnname #endif @@ -2952,7 +2934,7 @@ extern void make_byte_code (struct Lisp_Vector *); extern Lisp_Object Qautomatic_gc; extern Lisp_Object Qchar_table_extra_slots; extern struct Lisp_Vector *allocate_vector (EMACS_INT); -extern struct Lisp_Vector *allocate_pseudovector (int memlen, int lisplen, int tag); +extern struct Lisp_Vector *allocate_pseudovector (int, int, enum pvec_type); #define ALLOCATE_PSEUDOVECTOR(typ,field,tag) \ ((typ*) \ allocate_pseudovector \ diff --git a/src/lread.c b/src/lread.c index 9474462027..3a82e0057e 100644 --- a/src/lread.c +++ b/src/lread.c @@ -3981,7 +3981,7 @@ defsubr (struct Lisp_Subr *sname) { Lisp_Object sym, tem; sym = intern_c_string (sname->symbol_name); - XSETTYPED_PVECTYPE (sname, size, PVEC_SUBR); + XSETPVECTYPE (sname, PVEC_SUBR); XSETSUBR (tem, sname); set_symbol_function (sym, tem); } -- 2.20.1