summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDmitry Antipov <dmantipov@yandex.ru>2012-11-08 18:10:28 +0400
committerDmitry Antipov <dmantipov@yandex.ru>2012-11-08 18:10:28 +0400
commit914adc427f7d1159356e465ec616c65a2ea902af (patch)
treea4af121088abea87624dd93640d1deb1dd54ea95 /src
parentd14bb752ea51331ce2fb459c6ffacd8b11f80bb0 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/.gdbinit25
-rw-r--r--src/ChangeLog47
-rw-r--r--src/alloc.c185
-rw-r--r--src/buffer.c9
-rw-r--r--src/buffer.h31
-rw-r--r--src/fns.c8
-rw-r--r--src/lisp.h114
-rw-r--r--src/lread.c2
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,5 +1,52 @@
2012-11-08 Dmitry Antipov <dmantipov@yandex.ru>
+ 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 <dmantipov@yandex.ru>
+
* keyboard.c (event_to_kboard): Do not dereference
frame_or_window field of SELECTION_REQUEST_EVENT
and SELECTION_CLEAR_EVENT events (Bug#12814).
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
<http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8546>. */
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);
}