=== modified file 'src/alloc.c' --- src/alloc.c 2012-10-10 15:31:21 +0000 +++ src/alloc.c 2012-10-11 06:09:56 +0000 @@ -2040,7 +2040,7 @@ 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,15 +2619,37 @@ #define VINDEX(nbytes) (((nbytes) - VBLOCK_BYTES_MIN) / roundup_size) +/* When V is on the free list, V->contents[0] is used as a pointer to + next vector on the free list. */ + +#define NEXT_IN_FREE_LIST(v) \ + (*(struct Lisp_Vector **)((char *) v + header_size)) + +/* For the large vector V, previous word is used as a pointer + to next large vector. */ + +#define NEXT_LARGE_VECTOR(v) \ + (*(struct Lisp_Vector **)((char *) v - sizeof (void *))) + +/* Convert from memory block used for large vector to the vector itself. */ + +#define LARGE_VECTOR_START(mem) \ + (struct Lisp_Vector *)((char *) mem + sizeof (void *)) + +/* Convert from large vector to it's memory block. */ + +#define LARGE_VECTOR_MEM(v) (void *)((char *) v - sizeof (void *)) + /* Common shortcut to setup vector on a free list. */ #define SETUP_ON_FREE_LIST(v, nbytes, index) \ do { \ - XSETPVECTYPESIZE (v, PVEC_FREE, nbytes); \ + XSETPVECTYPESIZE (v, PVEC_FREE, 0, \ + ((nbytes) - header_size) / word_size); \ eassert ((nbytes) % roundup_size == 0); \ (index) = VINDEX (nbytes); \ eassert ((index) < VECTOR_MAX_FREE_LIST_INDEX); \ - (v)->header.next.vector = vector_free_lists[index]; \ + NEXT_IN_FREE_LIST (v) = vector_free_lists[index]; \ vector_free_lists[index] = (v); \ total_free_vector_slots += (nbytes) / word_size; \ } while (0) @@ -2706,8 +2728,7 @@ 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,8 +2742,7 @@ { /* 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, @@ -2739,7 +2759,6 @@ /* 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. */ @@ -2759,15 +2778,27 @@ ((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) +/* Return the memory footprint of V in bytes. */ + +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)) + return (bool_header_size + + (((struct Lisp_Bool_Vector *) v)->size + + BOOL_VECTOR_BITS_PER_CHAR - 1) + / BOOL_VECTOR_BITS_PER_CHAR); + return (header_size + + ((size & PSEUDOVECTOR_SIZE_MASK) + + ((size & PSEUDOVECTOR_REST_MASK) + >> PSEUDOVECTOR_SIZE_BITS)) * word_size); + } + return header_size + size * word_size; +} /* Reclaim space used by unmarked vectors. */ @@ -2785,6 +2816,7 @@ 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 +2825,16 @@ { 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 +2844,7 @@ { if (VECTOR_MARKED_P (next)) break; - nbytes = PSEUDOVECTOR_NBYTES (next); + nbytes = vector_nbytes (next); total_bytes += nbytes; next = ADVANCE (next, nbytes); } @@ -2867,12 +2901,15 @@ else total_vector_slots += header_size / word_size + vector->header.size; - vprev = &vector->header.next.vector; + vprev = &NEXT_LARGE_VECTOR (vector); } else { - *vprev = vector->header.next.vector; - lisp_free (vector); + *vprev = NEXT_LARGE_VECTOR (vector); +#if GC_MARK_STACK && !defined GC_MALLOC_CHECK + mem_delete (mem_find (vector)); +#endif + xfree (LARGE_VECTOR_MEM (vector)); } } } @@ -2904,8 +2941,15 @@ p = allocate_vector_from_block (vroundup (nbytes)); else { - p = lisp_malloc (nbytes, MEM_TYPE_VECTORLIKE); - p->header.next.vector = large_vectors; + void *mem; + /* Can't use lisp_malloc for P because + NEXT_LARGE_VECTOR (P) is outside of P. */ + mem = xmalloc (nbytes + sizeof (void *)); + p = LARGE_VECTOR_START (mem); +#if GC_MARK_STACK && !defined GC_MALLOC_CHECK + mem_insert (p, (char *) p + nbytes, MEM_TYPE_VECTORLIKE); +#endif + NEXT_LARGE_VECTOR (p) = large_vectors; large_vectors = p; } @@ -2952,7 +2996,7 @@ for (i = 0; i < lisplen; ++i) v->contents[i] = Qnil; - XSETPVECTYPESIZE (v, tag, lisplen); + XSETPVECTYPESIZE (v, tag, lisplen, memlen - lisplen); return v; } @@ -2961,10 +3005,9 @@ { 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,13 +4111,10 @@ 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) @@ -5687,7 +5727,7 @@ 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 +6357,7 @@ 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 +6366,7 @@ /* 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; } } === modified file 'src/buffer.c' --- src/buffer.c 2012-10-02 02:43:53 +0000 +++ src/buffer.c 2012-10-11 05:57:04 +0000 @@ -5107,11 +5107,6 @@ 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); @@ -5134,8 +5129,8 @@ /* 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! */ === modified file 'src/buffer.h' --- src/buffer.h 2012-09-11 04:22:03 +0000 +++ src/buffer.h 2012-10-11 05:56:43 +0000 @@ -482,11 +482,6 @@ 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 @@ 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,26 @@ 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. */ + +#define BUFFER_REST_SIZE \ + ((sizeof (struct buffer) - header_size) / word_size - BUFFER_LISP_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))) @@ -970,7 +988,7 @@ /* 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. */ === modified file 'src/fns.c' --- src/fns.c 2012-10-01 18:59:52 +0000 +++ src/fns.c 2012-10-11 05:55:01 +0000 @@ -2076,9 +2076,8 @@ 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 @@ { 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); === modified file 'src/lisp.h' --- src/lisp.h 2012-10-10 20:09:47 +0000 +++ src/lisp.h 2012-10-11 06:24:07 +0000 @@ -361,14 +361,11 @@ 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 }; /* DATA_SEG_BITS forces extra bits to be or'd in with any pointers @@ -388,9 +385,18 @@ 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. */ @@ -566,13 +572,13 @@ /* 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) \ @@ -584,16 +590,14 @@ #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)) @@ -783,28 +787,6 @@ 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 - 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. */ @@ -978,15 +960,11 @@ /* 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); @@ -1667,7 +1645,7 @@ #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. */ @@ -1680,8 +1658,7 @@ #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) @@ -1870,8 +1847,8 @@ #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 @@ -1879,8 +1856,8 @@ #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 === modified file 'src/lread.c' --- src/lread.c 2012-10-05 05:57:24 +0000 +++ src/lread.c 2012-10-11 06:01:19 +0000 @@ -3978,7 +3978,7 @@ { 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); }