* src/lisp.h (enum pvec_type): Use fewer bits.
(PSEUDOVECTOR_SIZE_BITS): New constant.
(PSEUDOVECTOR_SIZE_MASK, PVEC_TYPE_MASK): Use it.
(XSETPVECTYPESIZE, XSETTYPED_PSEUDOVECTOR, DEFUN): Adapt code to
change in pvec_type.
(PSEUDOVECTOR_TYPEP): New macro.
(TYPED_PSEUDOVECTORP): Use it.
* src/fns.c (internal_equal): Adapt code to extract pvectype.
* src/emacs.c (gdb_pvec_type): Update type.
* src/alloc.c (PSEUDOVECTOR_NBYTES): New macro.
(VECTOR_FREE_LIST_SIZE_MASK): Remove (=> PSEUDOVECTOR_SIZE_MASK).
(VECTOR_FREE_LIST_FLAG): Remove (=> PVEC_FREE).
(SETUP_ON_FREE_LIST): Use XSETPVECTYPESIZE.
(sweep_vectors): Use it. Use local var `total_bytes' instead of
abusing vector->header.next.nbytes.
(live_vector_p): Use PVEC_TYPE.
(mark_object): Adapt code to extract pvectype. Use switch.
+2012-07-04 Stefan Monnier <monnier@iro.umontreal.ca>
+
+ Turn VECTOR_FREE_LIST_FLAG into PVEC_FREE.
+ * lisp.h (enum pvec_type): Use fewer bits.
+ (PSEUDOVECTOR_SIZE_BITS): New constant.
+ (PSEUDOVECTOR_SIZE_MASK, PVEC_TYPE_MASK): Use it.
+ (XSETPVECTYPESIZE, XSETTYPED_PSEUDOVECTOR, DEFUN): Adapt code to
+ change in pvec_type.
+ (PSEUDOVECTOR_TYPEP): New macro.
+ (TYPED_PSEUDOVECTORP): Use it.
+ * fns.c (internal_equal): Adapt code to extract pvectype.
+ * emacs.c (gdb_pvec_type): Update type.
+ * alloc.c (PSEUDOVECTOR_NBYTES): New macro.
+ (VECTOR_FREE_LIST_SIZE_MASK): Remove (=> PSEUDOVECTOR_SIZE_MASK).
+ (VECTOR_FREE_LIST_FLAG): Remove (=> PVEC_FREE).
+ (SETUP_ON_FREE_LIST): Use XSETPVECTYPESIZE.
+ (sweep_vectors): Use it. Use local var `total_bytes' instead of
+ abusing vector->header.next.nbytes.
+ (live_vector_p): Use PVEC_TYPE.
+ (mark_object): Adapt code to extract pvectype. Use switch.
+
2012-07-04 Paul Eggert <eggert@cs.ucla.edu>
* doprnt.c (doprnt): Don't assume string length fits in 'int'.
}
-/* Mark Lisp objects in interval I. */
+/* Mark Lisp objects in interval I. */
static void
mark_interval (register INTERVAL i, Lisp_Object dummy)
ptrdiff_t nbytes;
/* Check that the string size recorded in the string is the
- same as the one recorded in the sdata structure. */
+ same as the one recorded in the sdata structure. */
if (from->string)
CHECK_STRING_BYTES (from->string);
#define VECTOR_BLOCK_SIZE 4096
-/* This special value is used to calculate vector size when the vector is
- on a free list. It should be VECTOR_BLOCK_SIZE rounded up to nearest
- power of two, minus one. */
-
-#define VECTOR_FREE_LIST_SIZE_MASK 4095
-
/* Handy constants for vectorlike objects. */
enum
{
/* Verify assumptions described above. */
verify ((VECTOR_BLOCK_SIZE % roundup_size) == 0);
-verify ((VECTOR_FREE_LIST_SIZE_MASK + 1) >= VECTOR_BLOCK_SIZE);
-verify ((VECTOR_FREE_LIST_SIZE_MASK & (VECTOR_FREE_LIST_SIZE_MASK + 1)) == 0);
+verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS));
/* Round up X to nearest mult-of-ROUNDUP_SIZE. */
#define VECTOR_MAX_FREE_LIST_INDEX \
((VECTOR_BLOCK_BYTES - VBLOCK_BYTES_MIN) / roundup_size + 1)
-/* When the vector is on a free list, vectorlike_header.SIZE is set to
- this special value ORed with vector's memory footprint size. */
-
-#define VECTOR_FREE_LIST_FLAG (~(ARRAY_MARK_FLAG | PSEUDOVECTOR_FLAG \
- | VECTOR_FREE_LIST_SIZE_MASK))
-
/* Common shortcut to advance vector pointer over a block data. */
#define ADVANCE(v, nbytes) ((struct Lisp_Vector *) ((char *) (v) + (nbytes)))
#define SETUP_ON_FREE_LIST(v, nbytes, index) \
do { \
- (v)->header.size = VECTOR_FREE_LIST_FLAG | (nbytes); \
+ XSETPVECTYPESIZE (v, PVEC_FREE, nbytes); \
eassert ((nbytes) % roundup_size == 0); \
(index) = VINDEX (nbytes); \
eassert ((index) < VECTOR_MAX_FREE_LIST_INDEX); \
((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. */
+
+#define PSEUDOVECTOR_NBYTES(vector) \
+ (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_FREE) \
+ ? vector->header.size & PSEUDOVECTOR_SIZE_MASK \
+ : vector->header.next.nbytes);
+
/* Reclaim space used by unmarked vectors. */
static void
}
else
{
- ptrdiff_t nbytes;
+ ptrdiff_t nbytes = PSEUDOVECTOR_NBYTES (vector);
+ ptrdiff_t total_bytes = nbytes;
- if ((vector->header.size & VECTOR_FREE_LIST_FLAG)
- == VECTOR_FREE_LIST_FLAG)
- vector->header.next.nbytes =
- vector->header.size & VECTOR_FREE_LIST_SIZE_MASK;
-
- next = ADVANCE (vector, vector->header.next.nbytes);
+ next = ADVANCE (vector, nbytes);
/* While NEXT is not marked, try to coalesce with VECTOR,
thus making VECTOR of the largest possible size. */
{
if (VECTOR_MARKED_P (next))
break;
- if ((next->header.size & VECTOR_FREE_LIST_FLAG)
- == VECTOR_FREE_LIST_FLAG)
- nbytes = next->header.size & VECTOR_FREE_LIST_SIZE_MASK;
- else
- nbytes = next->header.next.nbytes;
- vector->header.next.nbytes += nbytes;
+ nbytes = PSEUDOVECTOR_NBYTES (next);
+ total_bytes += nbytes;
next = ADVANCE (next, nbytes);
}
- eassert (vector->header.next.nbytes % roundup_size == 0);
+ eassert (total_bytes % roundup_size == 0);
if (vector == (struct Lisp_Vector *) block->data
&& !VECTOR_IN_BLOCK (next, block))
space was coalesced into the only free vector. */
free_this_block = 1;
else
- SETUP_ON_FREE_LIST (vector, vector->header.next.nbytes, nbytes);
+ {
+ int tmp;
+ SETUP_ON_FREE_LIST (vector, total_bytes, tmp);
+ }
}
}
while (VECTOR_IN_BLOCK (vector, block)
&& vector <= (struct Lisp_Vector *) p)
{
- if ((vector->header.size & VECTOR_FREE_LIST_FLAG)
- == VECTOR_FREE_LIST_FLAG)
+ if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_FREE))
vector = ADVANCE (vector, (vector->header.size
- & VECTOR_FREE_LIST_SIZE_MASK));
+ & PSEUDOVECTOR_SIZE_MASK));
else if (vector == p)
return 1;
else
#endif /* GC_CHECK_MARKED_OBJECTS */
if (ptr->header.size & PSEUDOVECTOR_FLAG)
- pvectype = ptr->header.size & PVEC_TYPE_MASK;
+ pvectype = ((ptr->header.size & PVEC_TYPE_MASK)
+ >> PSEUDOVECTOR_SIZE_BITS);
else
pvectype = 0;
if (pvectype != PVEC_SUBR && pvectype != PVEC_BUFFER)
CHECK_LIVE (live_vector_p);
- if (pvectype == PVEC_BUFFER)
+ switch (pvectype)
{
+ case PVEC_BUFFER:
#ifdef GC_CHECK_MARKED_OBJECTS
if (po != &buffer_defaults && po != &buffer_local_symbols)
{
}
#endif /* GC_CHECK_MARKED_OBJECTS */
mark_buffer ((struct buffer *) ptr);
- }
+ break;
- else if (pvectype == PVEC_COMPILED)
- /* We could treat this just like a vector, but it is better
- to save the COMPILED_CONSTANTS element for last and avoid
- recursion there. */
- {
- int size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK;
- int i;
+ case PVEC_COMPILED:
+ { /* We could treat this just like a vector, but it is better
+ to save the COMPILED_CONSTANTS element for last and avoid
+ recursion there. */
+ int size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK;
+ int i;
+
+ VECTOR_MARK (ptr);
+ for (i = 0; i < size; i++)
+ if (i != COMPILED_CONSTANTS)
+ mark_object (ptr->contents[i]);
+ if (size > COMPILED_CONSTANTS)
+ {
+ obj = ptr->contents[COMPILED_CONSTANTS];
+ goto loop;
+ }
+ }
+ break;
- VECTOR_MARK (ptr);
- for (i = 0; i < size; i++)
- if (i != COMPILED_CONSTANTS)
- mark_object (ptr->contents[i]);
- obj = ptr->contents[COMPILED_CONSTANTS];
- goto loop;
- }
+ case PVEC_FRAME:
+ {
+ mark_vectorlike (ptr);
+ mark_face_cache (((struct frame *) ptr)->face_cache);
+ }
+ break;
- else if (pvectype == PVEC_FRAME)
- {
- mark_vectorlike (ptr);
- mark_face_cache (((struct frame *) ptr)->face_cache);
- }
+ case PVEC_WINDOW:
+ {
+ struct window *w = (struct window *) ptr;
- else if (pvectype == PVEC_WINDOW)
- {
- struct window *w = (struct window *) ptr;
+ mark_vectorlike (ptr);
+ /* Mark glyphs for leaf windows. Marking window
+ matrices is sufficient because frame matrices
+ use the same glyph memory. */
+ if (NILP (w->hchild) && NILP (w->vchild) && w->current_matrix)
+ {
+ mark_glyph_matrix (w->current_matrix);
+ mark_glyph_matrix (w->desired_matrix);
+ }
+ }
+ break;
- mark_vectorlike (ptr);
- /* Mark glyphs for leaf windows. Marking window
- matrices is sufficient because frame matrices
- use the same glyph memory. */
- if (NILP (w->hchild) && NILP (w->vchild) && w->current_matrix)
- {
- mark_glyph_matrix (w->current_matrix);
- mark_glyph_matrix (w->desired_matrix);
- }
- }
+ case PVEC_HASH_TABLE:
+ {
+ struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *) ptr;
- else if (pvectype == PVEC_HASH_TABLE)
- {
- struct Lisp_Hash_Table *h = (struct Lisp_Hash_Table *) ptr;
+ mark_vectorlike (ptr);
+ /* If hash table is not weak, mark all keys and values.
+ For weak tables, mark only the vector. */
+ if (NILP (h->weak))
+ mark_object (h->key_and_value);
+ else
+ VECTOR_MARK (XVECTOR (h->key_and_value));
+ }
+ break;
- mark_vectorlike (ptr);
- /* If hash table is not weak, mark all keys and values.
- For weak tables, mark only the vector. */
- if (NILP (h->weak))
- mark_object (h->key_and_value);
- else
- VECTOR_MARK (XVECTOR (h->key_and_value));
- }
+ case PVEC_CHAR_TABLE:
+ mark_char_table (ptr);
+ break;
+
+ case PVEC_BOOL_VECTOR:
+ /* No Lisp_Objects to mark in a bool vector. */
+ VECTOR_MARK (ptr);
+ break;
- else if (pvectype == PVEC_CHAR_TABLE)
- mark_char_table (ptr);
+ case PVEC_SUBR:
+ break;
- else if (pvectype == PVEC_BOOL_VECTOR)
- /* No Lisp_Objects to mark in a bool vector. */
- VECTOR_MARK (ptr);
+ case PVEC_FREE:
+ abort ();
- else if (pvectype != PVEC_SUBR)
- mark_vectorlike (ptr);
+ default:
+ mark_vectorlike (ptr);
+ }
}
break;
ptrdiff_t gdb_array_mark_flag EXTERNALLY_VISIBLE = ARRAY_MARK_FLAG;
/* GDB might say "No enum type named pvec_type" if we don't have at
least one symbol with that type, and then xbacktrace could fail. */
-enum pvec_type gdb_pvec_type EXTERNALLY_VISIBLE = PVEC_TYPE_MASK;
+ptrdiff_t gdb_pvec_type EXTERNALLY_VISIBLE = PVEC_TYPE_MASK;
/* Empty lisp strings. To avoid having to build any others. */
Lisp_Object empty_unibyte_string, empty_multibyte_string;
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)))
+ if (!(size & ((PVEC_COMPILED | PVEC_CHAR_TABLE
+ | PVEC_SUB_CHAR_TABLE | PVEC_FONT)
+ << PSEUDOVECTOR_SIZE_BITS)))
return 0;
size &= PSEUDOVECTOR_SIZE_MASK;
}
It is not crucial, but there are plenty of bits here, so why not do it? */
enum pvec_type
{
- PVEC_NORMAL_VECTOR = 0,
- PVEC_PROCESS = 0x200,
- PVEC_FRAME = 0x400,
- PVEC_COMPILED = 0x800,
- PVEC_WINDOW = 0x1000,
- PVEC_WINDOW_CONFIGURATION = 0x2000,
- PVEC_SUBR = 0x4000,
- PVEC_CHAR_TABLE = 0x8000,
- PVEC_BOOL_VECTOR = 0x10000,
- PVEC_BUFFER = 0x20000,
- PVEC_HASH_TABLE = 0x40000,
- PVEC_TERMINAL = 0x80000,
- PVEC_SUB_CHAR_TABLE = 0x100000,
- PVEC_FONT = 0x200000,
- PVEC_OTHER = 0x400000,
- PVEC_TYPE_MASK = 0x7ffe00
-
-#if 0 /* This is used to make the value of PSEUDOVECTOR_FLAG available to
- GDB. It doesn't work on OS Alpha. Moved to a variable in
- emacs.c. */
- PVEC_FLAG = PSEUDOVECTOR_FLAG
-#endif
+ PVEC_NORMAL_VECTOR = 0, /* Unused! */
+ PVEC_FREE,
+ PVEC_PROCESS,
+ PVEC_FRAME,
+ PVEC_WINDOW,
+ PVEC_BOOL_VECTOR,
+ PVEC_BUFFER,
+ PVEC_HASH_TABLE,
+ PVEC_TERMINAL,
+ 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
};
/* For convenience, we also store the number of elements in these bits.
only the number of Lisp_Object fields (that need to be traced by the GC).
The distinction is used e.g. by Lisp_Process which places extra
non-Lisp_Object fields at the end of the structure. */
-#define PSEUDOVECTOR_SIZE_MASK 0x1ff
+#define PSEUDOVECTOR_SIZE_BITS 16
+#define PSEUDOVECTOR_SIZE_MASK ((1 << PSEUDOVECTOR_SIZE_BITS) - 1)
+#define PVEC_TYPE_MASK (0x0fff << PSEUDOVECTOR_SIZE_BITS)
/* Number of bits to put in each character in the internal representation
of bool vectors. This should not vary across implementations. */
#define XSETPVECTYPE(v, code) XSETTYPED_PVECTYPE (v, header.size, code)
#define XSETTYPED_PVECTYPE(v, size_member, code) \
- ((v)->size_member |= PSEUDOVECTOR_FLAG | (code))
+ ((v)->size_member |= PSEUDOVECTOR_FLAG | ((code) << PSEUDOVECTOR_SIZE_BITS))
#define XSETPVECTYPESIZE(v, code, sizeval) \
- ((v)->header.size = PSEUDOVECTOR_FLAG | (code) | (sizeval))
+ ((v)->header.size = (PSEUDOVECTOR_FLAG \
+ | ((code) << PSEUDOVECTOR_SIZE_BITS) \
+ | (sizeval)))
/* The cast to struct vectorlike_header * avoids aliasing issues. */
#define XSETPSEUDOVECTOR(a, b, code) \
#define XSETTYPED_PSEUDOVECTOR(a, b, size, code) \
(XSETVECTOR (a, b), \
eassert ((size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK)) \
- == (PSEUDOVECTOR_FLAG | (code))))
+ == (PSEUDOVECTOR_FLAG | (code << PSEUDOVECTOR_SIZE_BITS))))
#define XSETWINDOW_CONFIGURATION(a, b) \
(XSETPSEUDOVECTOR (a, b, PVEC_WINDOW_CONFIGURATION))
/* Set text properties. */
#define STRING_SET_INTERVALS(STR, INT) (XSTRING (STR)->intervals = (INT))
-/* In a string or vector, the sign bit of the `size' is the gc mark bit */
+/* In a string or vector, the sign bit of the `size' is the gc mark bit. */
struct Lisp_String
{
ptrdiff_t size;
ptrdiff_t size_byte;
- INTERVAL intervals; /* text properties in this string */
+ INTERVAL intervals; /* Text properties in this string. */
unsigned char *data;
};
<http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8546>. */
struct vectorlike_header
{
+ /* This 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. */
ptrdiff_t size;
/* When the vector is allocated from a vector block, NBYTES is used
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;
};
of the shortest vector that would hold that struct. */
#define VECSIZE(type) ((sizeof (type) \
- offsetof (struct Lisp_Vector, contents[0]) \
- + sizeof (Lisp_Object) - 1) /* round up */ \
+ + sizeof (Lisp_Object) - 1) /* Round up. */ \
/ sizeof (Lisp_Object))
/* Like VECSIZE, but used when the pseudo-vector has non-Lisp_Object fields
/* True if object X is a pseudovector whose code is CODE. The cast to struct
vectorlike_header * avoids aliasing issues. */
#define PSEUDOVECTORP(x, code) \
- TYPED_PSEUDOVECTORP(x, vectorlike_header, code)
+ TYPED_PSEUDOVECTORP (x, vectorlike_header, code)
+
+#define PSEUDOVECTOR_TYPEP(v, code) \
+ (((v)->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK)) \
+ == (PSEUDOVECTOR_FLAG | ((code) << PSEUDOVECTOR_SIZE_BITS)))
/* True if object X, with internal type struct T *, is a pseudovector whose
code is CODE. */
#define TYPED_PSEUDOVECTORP(x, t, code) \
(VECTORLIKEP (x) \
- && (((((struct t *) XUNTAG (x, Lisp_Vectorlike))->size \
- & (PSEUDOVECTOR_FLAG | (code)))) \
- == (PSEUDOVECTOR_FLAG | (code))))
+ && PSEUDOVECTOR_TYPEP ((struct t *) XUNTAG (x, Lisp_Vectorlike), code))
/* Test for specific pseudovector types. */
#define WINDOW_CONFIGURATIONP(x) PSEUDOVECTORP (x, PVEC_WINDOW_CONFIGURATION)
#define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc) \
Lisp_Object fnname DEFUN_ARGS_ ## maxargs ; \
static DECL_ALIGN (struct Lisp_Subr, sname) = \
- { PVEC_SUBR | (sizeof (struct Lisp_Subr) / sizeof (EMACS_INT)), \
+ { (PVEC_SUBR << PSEUDOVECTOR_SIZE_BITS) \
+ | (sizeof (struct Lisp_Subr) / sizeof (EMACS_INT)), \
{ (Lisp_Object (__cdecl *)(void))fnname }, \
minargs, maxargs, lname, intspec, 0}; \
Lisp_Object fnname
#define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc) \
Lisp_Object fnname DEFUN_ARGS_ ## maxargs ; \
static DECL_ALIGN (struct Lisp_Subr, sname) = \
- { PVEC_SUBR, \
+ { PVEC_SUBR << PSEUDOVECTOR_SIZE_BITS, \
{ .a ## maxargs = fnname }, \
minargs, maxargs, lname, intspec, 0}; \
Lisp_Object fnname