unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0
@ 2011-04-25  7:41 Paul Eggert
  2011-04-25 10:23 ` Eli Zaretskii
  2011-04-25 14:05 ` Stefan Monnier
  0 siblings, 2 replies; 7+ messages in thread
From: Paul Eggert @ 2011-04-25  7:41 UTC (permalink / raw)
  To: 8546

[-- Attachment #1: Type: text/plain, Size: 3661 bytes --]

Emacs's pseudovector implementation occasionally runs afoul of
optimizations introduced by version 4.6.0 of GCC, and this can break
Emacs.  Luckily there's a fix, which I would like to install after some more
testing.  I'm publishing it here now for a heads-up.

Another possible fix would be to disable the GCC optimizations.
However, this would no doubt make Emacs slower overall, and anyway the
optimizations are valid according to the rules of C which means that
non-GCC compilers may well be doing them too.  It's better to alter
Emacs to avoid the problem, since this is not too much trouble.

Here are more details about the problem.

Building Emacs 23.3 (as well as the Emacs trunk) on Ubuntu 10.10 x86
and GCC 4.6.0, with Emacs configured by "configure
--enable-checking=all", fails with the following symptoms:

  `/bin/pwd`/temacs --batch --load loadup bootstrap
  
  /home/eggert/junk/emacs-23.3/src/buffer.c:5177: Emacs fatal error: assertion failed: (XVECTOR (Vbuffer_defaults)->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK)) == (PSEUDOVECTOR_FLAG | (PVEC_BUFFER))
  Aborted

I tracked this down to an incompatibility between Emacs and GCC 4.6.0
on the x86 with -O2 optimization.  GCC does a type-based aliasing
optimization, and reorders stores and loads to locations that cannot
possibly be the same location if the types are as the program says
they are.  Unfortunately, Emacs's pseudovector implementation dissembles
about the types and therefore runs afoul of the optimization.
Possibly there are subtle bugs induced by this, even when
--enable-checking is not used, but --enable-checking makes the problem
obvious.

Here's the source code, in buffer.c's init_buffer_once:

  reset_buffer_local_variables (&buffer_local_symbols, 1);
  /* Prevent GC from getting confused.  */
  buffer_defaults.text = &buffer_defaults.own_text;
  buffer_local_symbols.text = &buffer_local_symbols.own_text;
  BUF_INTERVALS (&buffer_defaults) = 0;
  BUF_INTERVALS (&buffer_local_symbols) = 0;
  XSETPVECTYPE (&buffer_defaults, PVEC_BUFFER);
  XSETBUFFER (Vbuffer_defaults, &buffer_defaults);

Here are the relevant definitions in lisp.h:

  #define XSETPVECTYPE(v,code) ((v)->size |= PSEUDOVECTOR_FLAG | (code))
  #define XSETBUFFER(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BUFFER))
  #define XSETPSEUDOVECTOR(a, b, code) \
    (XSETVECTOR (a, b),							\
     eassert ((XVECTOR (a)->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))	\
	      == (PSEUDOVECTOR_FLAG | (code))))

Here's the generated x86 code, with the problem highlighted:

		movl	$buffer_local_symbols, %eax
		movl	$1, %edx
		call	reset_buffer_local_variables
		movl	$buffer_defaults, %eax
		orl	$5, %eax
		movl	%eax, Vbuffer_defaults
		andl	$-8, %eax
	0=>	movl	(%eax), %eax
	1=>	orl	$1073872896, buffer_defaults
		movl	$buffer_defaults+8, buffer_defaults+76
		andl	$1082129920, %eax
	2=>	cmpl	$1073872896, %eax
		movl	$buffer_local_symbols+8, buffer_local_symbols+76
		movl	$0, buffer_defaults+64
		movl	$0, buffer_local_symbols+64
		je	.L2396
		movl	suppress_checking, %eax
		testl	%eax, %eax
		je	.L2398
	.L2396:

The code marked (1) implements the expansion of XSETPVECTYPE, and sets
buffer_defaults.size to 0x40020000, the mark for a buffer.  The code
marked (2) is part of the expansion of the eassert, and it checks that
XVECTOR (Vbuffer_defaults)->size has the proper flag and code.  But
(2) is relying on a *cached* copy of the size, which was loaded in (0),
and (0) precedes (1).  So, the assertion fails.

The patch is attached.  It's against my copy of Emacs, which has a few
other fixes that I haven't had time to merge to the trunk yet.  But it
should give a good feel for what's involved.


[-- Attachment #2: pseudovec.txt.gz --]
[-- Type: application/x-gzip, Size: 15400 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0
  2011-04-25  7:41 bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0 Paul Eggert
@ 2011-04-25 10:23 ` Eli Zaretskii
  2011-04-25 19:30   ` Paul Eggert
  2011-04-25 14:05 ` Stefan Monnier
  1 sibling, 1 reply; 7+ messages in thread
From: Eli Zaretskii @ 2011-04-25 10:23 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 8546

> Date: Mon, 25 Apr 2011 00:41:58 -0700
> From: Paul Eggert <eggert@cs.ucla.edu>
> 
>   #define XSETPSEUDOVECTOR(a, b, code) \
>     (XSETVECTOR (a, b),							\
>      eassert ((XVECTOR (a)->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))	\
> 	      == (PSEUDOVECTOR_FLAG | (code))))
> 
> Here's the generated x86 code, with the problem highlighted:
> 
> 		movl	$buffer_local_symbols, %eax
> 		movl	$1, %edx
> 		call	reset_buffer_local_variables
> 		movl	$buffer_defaults, %eax
> 		orl	$5, %eax
> 		movl	%eax, Vbuffer_defaults
> 		andl	$-8, %eax
> 	0=>	movl	(%eax), %eax
> 	1=>	orl	$1073872896, buffer_defaults
> 		movl	$buffer_defaults+8, buffer_defaults+76
> 		andl	$1082129920, %eax
> 	2=>	cmpl	$1073872896, %eax
> 		movl	$buffer_local_symbols+8, buffer_local_symbols+76
> 		movl	$0, buffer_defaults+64
> 		movl	$0, buffer_local_symbols+64
> 		je	.L2396
> 		movl	suppress_checking, %eax
> 		testl	%eax, %eax
> 		je	.L2398
> 	.L2396:
> 
> The code marked (1) implements the expansion of XSETPVECTYPE, and sets
> buffer_defaults.size to 0x40020000, the mark for a buffer.  The code
> marked (2) is part of the expansion of the eassert, and it checks that
> XVECTOR (Vbuffer_defaults)->size has the proper flag and code.  But
> (2) is relying on a *cached* copy of the size, which was loaded in (0),
> and (0) precedes (1).  So, the assertion fails.

Could you please tell more what is it in the Emacs macros that
triggers this problem?  You say that "Emacs's pseudovector
implementation dissembles about the types", but could you please point
out where in the code this happens?  I'm afraid I don't see it, but
then I'm no expert on compiler optimizations and on how they interact
with C types.

TIA





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0
  2011-04-25  7:41 bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0 Paul Eggert
  2011-04-25 10:23 ` Eli Zaretskii
@ 2011-04-25 14:05 ` Stefan Monnier
  2011-04-25 23:12   ` Paul Eggert
  1 sibling, 1 reply; 7+ messages in thread
From: Stefan Monnier @ 2011-04-25 14:05 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 8546

> The patch is attached.  It's against my copy of Emacs, which has a few
> other fixes that I haven't had time to merge to the trunk yet.  But it
> should give a good feel for what's involved.

[ Please don't compress patches for review.  57KB is not that large.  ]

Thanks for tackling this problem.  A few questions/comments on your
patch (which I haven't reviewed completely):

   +struct vector_header

I'd call it vectorlike_header.
   
   +  {
   +    EMACS_UINT size;
   +    union {
   +      struct buffer *buffer;
   +      struct Lisp_Vector *vector;
   +    } next;
   +  };

Why do you need to handle buffers specially here?  That sounds wrong.

   +#define XVECTOR_SIZE(a) (XVECTOR (a)->header.size + 0)

why not use ASIZE?

   +#define XVECTOR_HEADER_SIZE(a) (((struct vector_header *) XPNTR (a))->size + 0)

why do we need this variant with this weird set of type casts?

   +	* lread.c (defsubr): Use XSETTYPED_PVECTYPE, since Lisp_Subr is a
   +	special case.

Why does Lisp_Subr need to be a special case (IIUC this applies to
XSETTYPED_PSEUDOVECTOR and TYPED_PSEUDOVECTORP as well).

   +#define XSETPVECTYPESIZE(v, code, sizeval) \
   +  ((v)->header.size = PSEUDOVECTOR_FLAG | (code) | (sizeval))

Sounds good.


        Stefan





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0
  2011-04-25 10:23 ` Eli Zaretskii
@ 2011-04-25 19:30   ` Paul Eggert
  0 siblings, 0 replies; 7+ messages in thread
From: Paul Eggert @ 2011-04-25 19:30 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 8546

On 04/25/11 03:23, Eli Zaretskii wrote:
> Could you please tell more what is it in the Emacs macros that
> triggers this problem?  You say that "Emacs's pseudovector
> implementation dissembles about the types", but could you please point
> out where in the code this happens?

Sure.  First, let me briefly describe the optimization, which
is allowed by the C standard.  Here's an idealized example:

	struct a { int size; ...; };
	struct b { int size; ...; };
	struct a *p = ...;
        struct b *q = ...;
	p->size = 0;
	q->size = 1;
	return p->size;

ISO C allows a compiler to optimize the last statement
to "return 0;".  If P and Q point to the
same memory location, storing through P and loading through
Q results in undefined behavior, because P and Q are incompatible
types.  When the behavior is undefined, the compiler is allowed
to generate whatever code it likes, including the optimized code.

Most of Emacs is OK with this optimization.  However, the pseudovector
code currently does stuff like this when checking is enabled
(I am giving the preprocessor output of XSETPVECTYPE followed by
XSETBUFFER, and a simplified version of it assuming the x86
to make things clearer):

	struct buffer *b = ...;
	b->size |= 0x4020000;
	Lisp_Object o = (Lisp_Object) b;
	struct Lisp_Vector *v = (struct Lisp_Vector *) o;
	if ((v->size & 0x4020000) != 0x4020000)
	  abort ();

It's the conversion of struct buffer * to struct Lisp_Vector * that
results in undefined behavior, for the same reason that the
earlier example does: the code is reading a word via a struct Lisp_Vector *
pointer, which means that the compiler is free to (and GCC does) delay
the earlier store of that word until after the check, which means the code
aborts.





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0
  2011-04-25 14:05 ` Stefan Monnier
@ 2011-04-25 23:12   ` Paul Eggert
  2011-04-26 12:46     ` Stefan Monnier
  0 siblings, 1 reply; 7+ messages in thread
From: Paul Eggert @ 2011-04-25 23:12 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 8546

[-- Attachment #1: Type: text/plain, Size: 2474 bytes --]

On 04/25/11 07:05, Stefan Monnier wrote:
>    +struct vector_header
> 
> I'd call it vectorlike_header.

OK, I'll do that.

>    +#define XVECTOR_SIZE(a) (XVECTOR (a)->header.size + 0)
> 
> why not use ASIZE?

No good reason.  Thanks, I'll do that too.

>    +  {
>    +    EMACS_UINT size;
>    +    union {
>    +      struct buffer *buffer;
>    +      struct Lisp_Vector *vector;
>    +    } next;
>    +  };
> 
> Why do you need to handle buffers specially here?  That sounds wrong.

Purely as a convenience.  The code always uses the 'next' pointer as a
struct buffer * (in alloc.c, buffer.c, data.c), or as a struct
Lisp_Vector * (in alloc.c, fns.c).  As an alternative, we could
replace the above with

  {
    EMACS_UINT size;
    struct vectorlike_header *next;
  };

and then replace uses like this:

  for (b = all_buffers; b && b != po; b = b->header.next.buffer)

with uses like this:

  for (b = all_buffers; b && b != po; b = (struct buffer *) b->header.next)

I thought that the union made the code clearer and I know you
normally dislike casts, but if you prefer the style with casts it'd be
easy to do that too.

>    +#define XVECTOR_HEADER_SIZE(a) (((struct vector_header *) XPNTR (a))->size + 0)
> 
> why do we need this variant with this weird set of type casts?

I'll remove it.  It is used in only one place, in
XSETTYPED_PSEUDOVECTOR, where the idea is a key part of the
antialiasing fix.  But there's no need to break it out as a separate
macro, so I'll fold it into XSETTYPED_PSEUDOVECTOR.

>    +	* lread.c (defsubr): Use XSETTYPED_PVECTYPE, since Lisp_Subr is a
>    +	special case.
> 
> Why does Lisp_Subr need to be a special case (IIUC this applies to
> XSETTYPED_PSEUDOVECTOR and TYPED_PSEUDOVECTORP as well).

struct Lisp_Subr has a "size" field but no "next" field.  I didn't
change its layout to contain a struct vectorlike_header field, as that
would have added an extra word that isn't needed.  It would be safer,
from a C standards point of view, to spend the extra word and make
struct Lisp_Subr be like the other vector-like objects, but in
practice I doubt whether any practical optimizing compiler would break
that part of the code; so I kept it as a special case.

If you prefer the simpler and cleaner (but less space-efficient)
variant, where struct Lisp_Subr has a "next" field like all the other
vector-like data structures, that would be easy to do.

Attached is a revised patch with the above comments taken into account.


[-- Attachment #2: pseudovec-2.txt --]
[-- Type: text/plain, Size: 56428 bytes --]

=== modified file 'src/ChangeLog'
--- src/ChangeLog	2011-04-24 05:30:24 +0000
+++ src/ChangeLog	2011-04-25 21:50:24 +0000
@@ -1,3 +1,55 @@
+2011-04-25  Paul Eggert  <eggert@cs.ucla.edu>
+
+	lisp.h: Fix a problem with aliasing and vector headers.
+	GCC 4.6.0 optimizes based on type-based alias analysis.  For
+	example, if b is of type struct buffer * and v of type struct
+	Lisp_Vector *, then gcc -O2 was incorrectly assuming that &b->size
+	!= &v->size, and therefore "v->size = 1; b->size = 2; return
+	v->size;" must therefore return 1.  This assumption is incorrect
+	for Emacs, since it type-puns struct Lisp_Vector * with many other
+	types.  To fix this problem, this patch adds a new type struct
+	vectorlike_header that documents the constraints on layout of vectors
+	and pseudovectors, and helps optimizing compilers not get fooled
+	by Emacs's type punning.  It also adds the macros XSETTYPED_PVECTYPE
+	XSETTYPED_PSEUDOVECTOR, TYPED_PSEUDOVECTORP, for similar reasons.
+	* lisp.h (XSETTYPED_PVECTYPE): New macro, specifying the name of
+	the size member.
+	(XSETPVECTYPE): Rewrite in terms of new macro.
+	(XSETPVECTYPESIZE): New macro, specifying both type and size.
+	This is a bit clearer, and further avoids the possibility of
+	undesirable aliasing.
+	(XSETTYPED_PSEUDOVECTOR): New macro, specifying the size.
+	(XSETPSEUDOVECTOR): Rewrite in terms of XSETTYPED_PSEUDOVECTOR.
+	(XSETSUBR): Rewrite in terms of XSETTYPED_PSEUDOVECTOR and XSIZE,
+	since Lisp_Subr is a special case (no "next" field).
+	(ASIZE): Now uses header.size rather than size.  All
+	previous uses of XVECTOR (foo)->size replaced to use this macro,
+	to avoid the hassle of writing XVECTOR (foo)->header.size.
+	(struct vectorlike_header): New type.
+	(TYPED_PSEUDOVECTORP): New macro, also specifying the C type of the
+	object, to help avoid aliasing.
+	(PSEUDOVECTORP): Rewrite in terms of TYPED_PSEUDOVECTORP.
+	(SUBRP): Likewise, since Lisp_Subr is a special case.
+	* lisp.h (struct Lisp_Vector, struct Lisp_Char_Table):
+	(struct Lisp_Sub_Char_Table, struct Lisp_Bool_Vector):
+	(struct Lisp_Hash_Table): Combine first two members into a single
+	struct vectorlike_header member.  All uses of "size" and "next" members
+	changed to be "header.size" and "header.next".
+	* buffer.h (struct buffer): Likewise.
+	* font.h (struct font_spec, struct font_entity, struct font): Likewise.
+	* frame.h (struct frame): Likewise.
+	* process.h (struct Lisp_Process): Likewise.
+	* termhooks.h (struct terminal): Likewise.
+	* window.c (struct save_window_data, struct saved_window): Likewise.
+	* window.h (struct window): Likewise.
+	* alloc.c (allocate_buffer, Fmake_bool_vector, allocate_pseudovector):
+	Use XSETPVECTYPESIZE, not XSETPVECTYPE, to avoid aliasing problems.
+	* buffer.c (init_buffer_once): Likewise.
+	* lread.c (defsubr): Use XSETTYPED_PVECTYPE, since Lisp_Subr is a
+	special case.
+	* process.c (Fformat_network_address): Use local var for size,
+	for brevity.
+
 2011-04-24  Paul Eggert  <eggert@cs.ucla.edu>
 
 	* bytecode.c (exec_byte_code): Don't use XVECTOR before CHECK_VECTOR.

=== modified file 'src/lisp.h'
--- src/lisp.h	2011-04-21 06:03:09 +0000
+++ src/lisp.h	2011-04-25 21:38:32 +0000
@@ -601,17 +601,26 @@
 
 /* Pseudovector types.  */
 
-#define XSETPVECTYPE(v,code) ((v)->size |= PSEUDOVECTOR_FLAG | (code))
+#define XSETPVECTYPE(v, code) XSETTYPED_PVECTYPE(v, header.size, code)
+#define XSETTYPED_PVECTYPE(v, size_member, code) \
+  ((v)->size_member |= PSEUDOVECTOR_FLAG | (code))
+#define XSETPVECTYPESIZE(v, code, sizeval) \
+  ((v)->header.size = PSEUDOVECTOR_FLAG | (code) | (sizeval))
 #define XSETPSEUDOVECTOR(a, b, code) \
+  XSETTYPED_PSEUDOVECTOR(a, b,       \
+			 ((struct vectorlike_header *) XPNTR (a))->size, \
+			 code)
+#define XSETTYPED_PSEUDOVECTOR(a, b, size, code)			\
   (XSETVECTOR (a, b),							\
-   eassert ((XVECTOR (a)->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))	\
+   eassert ((size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))		\
 	    == (PSEUDOVECTOR_FLAG | (code))))
 #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))
-#define XSETSUBR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUBR))
+#define XSETSUBR(a, b) \
+  XSETTYPED_PSEUDOVECTOR (a, b, XSUBR (a)->size, 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))
@@ -621,7 +630,7 @@
 /* Convenience macros for dealing with Lisp arrays.  */
 
 #define AREF(ARRAY, IDX)	XVECTOR ((ARRAY))->contents[IDX]
-#define ASIZE(ARRAY)		XVECTOR ((ARRAY))->size
+#define ASIZE(ARRAY)		XVECTOR ((ARRAY))->header.size
 /* The IDX==IDX tries to detect when the macro argument is side-effecting.  */
 #define ASET(ARRAY, IDX, VAL)	\
   (eassert ((IDX) == (IDX)),				\
@@ -778,10 +787,21 @@
     unsigned char *data;
   };
 
+/* Header of vector-like objects.  This type documents the constraints on
+   layout of vectors and pseudovectors, and helps optimizing compilers not get
+   fooled by Emacs's type punning.  */
+struct vectorlike_header
+  {
+    EMACS_UINT size;
+    union {
+      struct buffer *buffer;
+      struct Lisp_Vector *vector;
+    } next;
+  };
+
 struct Lisp_Vector
   {
-    EMACS_UINT size;
-    struct Lisp_Vector *next;
+    struct vectorlike_header header;
     Lisp_Object contents[1];
   };
 
@@ -817,7 +837,7 @@
 /* Return the number of "extra" slots in the char table CT.  */
 
 #define CHAR_TABLE_EXTRA_SLOTS(CT)	\
-  (((CT)->size & PSEUDOVECTOR_SIZE_MASK) - CHAR_TABLE_STANDARD_SLOTS)
+  (((CT)->header.size & PSEUDOVECTOR_SIZE_MASK) - CHAR_TABLE_STANDARD_SLOTS)
 
 #ifdef __GNUC__
 
@@ -882,12 +902,11 @@
 
 struct Lisp_Char_Table
   {
-    /* This is the vector's size field, which also holds the
+    /* HEADER.SIZE is the vector's size field, which also holds the
        pseudovector type information.  It holds the size, too.
        The size counts the defalt, parent, purpose, ascii,
        contents, and extras slots.  */
-    EMACS_UINT size;
-    struct Lisp_Vector *next;
+    struct vectorlike_header header;
 
     /* This holds a default value,
        which is used whenever the value for a specific character is nil.  */
@@ -914,10 +933,9 @@
 
 struct Lisp_Sub_Char_Table
   {
-    /* This is the vector's size field, which also holds the
+    /* HEADER.SIZE is the vector's size field, which also holds the
        pseudovector type information.  It holds the size, too.  */
-    EMACS_INT size;
-    struct Lisp_Vector *next;
+    struct vectorlike_header header;
 
     /* Depth of this sub char-table.  It should be 1, 2, or 3.  A sub
        char-table of depth 1 contains 16 elements, and each element
@@ -936,10 +954,9 @@
 /* A boolvector is a kind of vectorlike, with contents are like a string.  */
 struct Lisp_Bool_Vector
   {
-    /* This is the vector's size field.  It doesn't have the real size,
+    /* HEADER.SIZE is the vector's size field.  It doesn't have the real size,
        just the subtype information.  */
-    EMACS_UINT vector_size;
-    struct Lisp_Vector *next;
+    struct vectorlike_header header;
     /* This is the size in bits.  */
     EMACS_UINT size;
     /* This contains the actual bits, packed into bytes.  */
@@ -952,7 +969,7 @@
 
    This type is treated in most respects as a pseudovector,
    but since we never dynamically allocate or free them,
-   we don't need a next-vector field.  */
+   we don't need a struct vectorlike_header and its 'next' field.  */
 
 struct Lisp_Subr
   {
@@ -1099,9 +1116,8 @@
 
 struct Lisp_Hash_Table
 {
-  /* Vector fields.  The hash table code doesn't refer to these.  */
-  EMACS_UINT size;
-  struct Lisp_Vector *vec_next;
+  /* This is for Lisp; the hash table code does not refer to it.  */
+  struct vectorlike_header header;
 
   /* Function used to compare keys.  */
   Lisp_Object test;
@@ -1202,7 +1218,7 @@
 
 /* Value is the size of hash table H.  */
 
-#define HASH_TABLE_SIZE(H) XVECTOR ((H)->next)->size
+#define HASH_TABLE_SIZE(H) ASIZE ((H)->next)
 
 /* Default size for hash tables if not specified.  */
 
@@ -1620,7 +1636,7 @@
 #define CONSP(x) (XTYPE ((x)) == Lisp_Cons)
 
 #define FLOATP(x) (XTYPE ((x)) == Lisp_Float)
-#define VECTORP(x)    (VECTORLIKEP (x) && !(XVECTOR (x)->size & PSEUDOVECTOR_FLAG))
+#define VECTORP(x) (VECTORLIKEP (x) && !(ASIZE (x) & PSEUDOVECTOR_FLAG))
 #define OVERLAYP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Overlay)
 #define MARKERP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Marker)
 #define SAVE_VALUEP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Save_Value)
@@ -1633,8 +1649,14 @@
 
 /* True if object X is a pseudovector whose code is CODE.  */
 #define PSEUDOVECTORP(x, code)					\
+  TYPED_PSEUDOVECTORP(x, vectorlike_header, code)
+
+/* True if object X, with internal type struct T *, is a pseudovector whose
+   code is CODE.  */
+#define TYPED_PSEUDOVECTORP(x, t, code)				\
   (VECTORLIKEP (x)						\
-   && (((XVECTOR (x)->size & (PSEUDOVECTOR_FLAG | (code))))	\
+   && (((((struct t *) XPNTR (x))->size				\
+	 & (PSEUDOVECTOR_FLAG | (code))))			\
        == (PSEUDOVECTOR_FLAG | (code))))
 
 /* Test for specific pseudovector types.  */
@@ -1642,7 +1664,7 @@
 #define PROCESSP(x) PSEUDOVECTORP (x, PVEC_PROCESS)
 #define WINDOWP(x) PSEUDOVECTORP (x, PVEC_WINDOW)
 #define TERMINALP(x) PSEUDOVECTORP (x, PVEC_TERMINAL)
-#define SUBRP(x) PSEUDOVECTORP (x, PVEC_SUBR)
+#define SUBRP(x) TYPED_PSEUDOVECTORP (x, Lisp_Subr, 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)

=== modified file 'src/alloc.c'
--- src/alloc.c	2011-04-20 07:11:43 +0000
+++ src/alloc.c	2011-04-25 21:34:39 +0000
@@ -146,9 +146,9 @@
 #define UNMARK_STRING(S)	((S)->size &= ~ARRAY_MARK_FLAG)
 #define STRING_MARKED_P(S)	(((S)->size & ARRAY_MARK_FLAG) != 0)
 
-#define VECTOR_MARK(V)		((V)->size |= ARRAY_MARK_FLAG)
-#define VECTOR_UNMARK(V)	((V)->size &= ~ARRAY_MARK_FLAG)
-#define VECTOR_MARKED_P(V)	(((V)->size & ARRAY_MARK_FLAG) != 0)
+#define VECTOR_MARK(V)		((V)->header.size |= ARRAY_MARK_FLAG)
+#define VECTOR_UNMARK(V)	((V)->header.size &= ~ARRAY_MARK_FLAG)
+#define VECTOR_MARKED_P(V)	(((V)->header.size & ARRAY_MARK_FLAG) != 0)
 
 /* Value is the number of bytes of S, a pointer to a struct Lisp_String.
    Be careful during GC, because S->size contains the mark bit for
@@ -1055,9 +1055,9 @@
   struct buffer *b
     = (struct buffer *) lisp_malloc (sizeof (struct buffer),
 				     MEM_TYPE_BUFFER);
-  b->size = ((sizeof (struct buffer) + sizeof (EMACS_INT) - 1)
-	     / sizeof (EMACS_INT));
-  XSETPVECTYPE (b, PVEC_BUFFER);
+  XSETPVECTYPESIZE (b, PVEC_BUFFER,
+		    ((sizeof (struct buffer) + sizeof (EMACS_INT) - 1)
+		     / sizeof (EMACS_INT)));
   return b;
 }
 
@@ -2244,10 +2244,8 @@
      slot `size' of the struct Lisp_Bool_Vector.  */
   val = Fmake_vector (make_number (length_in_elts + 1), Qnil);
 
-  /* Get rid of any bits that would cause confusion.  */
-  XVECTOR (val)->size = 0;	/* No Lisp_Object to trace in there.  */
-  /* Use  XVECTOR (val) rather than `p' because p->size is not TRT. */
-  XSETPVECTYPE (XVECTOR (val), PVEC_BOOL_VECTOR);
+  /* No Lisp_Object to trace in there.  */
+  XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0);
 
   p = XBOOL_VECTOR (val);
   p->size = XFASTINT (length);
@@ -2814,7 +2812,7 @@
   consing_since_gc += nbytes;
   vector_cells_consed += len;
 
-  p->next = all_vectors;
+  p->header.next.vector = all_vectors;
   all_vectors = p;
 
   MALLOC_UNBLOCK_INPUT;
@@ -2830,7 +2828,7 @@
 allocate_vector (EMACS_INT nslots)
 {
   struct Lisp_Vector *v = allocate_vectorlike (nslots);
-  v->size = nslots;
+  v->header.size = nslots;
   return v;
 }
 
@@ -2844,11 +2842,10 @@
   EMACS_INT i;
 
   /* Only the first lisplen slots will be traced normally by the GC.  */
-  v->size = lisplen;
   for (i = 0; i < lisplen; ++i)
     v->contents[i] = Qnil;
 
-  XSETPVECTYPE (v, tag);	/* Add the appropriate tag.  */
+  XSETPVECTYPESIZE (v, tag, lisplen);
   return v;
 }
 
@@ -4737,7 +4734,7 @@
 
   p = (struct Lisp_Vector *) pure_alloc (size, Lisp_Vectorlike);
   XSETVECTOR (new, p);
-  XVECTOR (new)->size = len;
+  XVECTOR (new)->header.size = len;
   return new;
 }
 
@@ -4775,7 +4772,7 @@
       register EMACS_INT i;
       EMACS_INT size;
 
-      size = XVECTOR (obj)->size;
+      size = ASIZE (obj);
       if (size & PSEUDOVECTOR_FLAG)
 	size &= PSEUDOVECTOR_SIZE_MASK;
       vec = XVECTOR (make_pure_vector (size));
@@ -4899,7 +4896,7 @@
 	      }
 	  }
 
-	nextb = nextb->next;
+	nextb = nextb->header.next.buffer;
       }
   }
 
@@ -5054,7 +5051,7 @@
 	   undo_list any more, we can finally mark the list.  */
 	mark_object (nextb->BUFFER_INTERNAL_FIELD (undo_list));
 
-	nextb = nextb->next;
+	nextb = nextb->header.next.buffer;
       }
   }
 
@@ -5228,7 +5225,7 @@
 static void
 mark_vectorlike (struct Lisp_Vector *ptr)
 {
-  register EMACS_UINT size = ptr->size;
+  register EMACS_UINT size = ptr->header.size;
   register EMACS_UINT i;
 
   eassert (!VECTOR_MARKED_P (ptr));
@@ -5251,7 +5248,7 @@
 static void
 mark_char_table (struct Lisp_Vector *ptr)
 {
-  register EMACS_UINT size = ptr->size & PSEUDOVECTOR_SIZE_MASK;
+  register EMACS_UINT size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK;
   register EMACS_UINT i;
 
   eassert (!VECTOR_MARKED_P (ptr));
@@ -5364,7 +5361,7 @@
 	  if (po != &buffer_defaults && po != &buffer_local_symbols)
 	    {
 	      struct buffer *b;
-	      for (b = all_buffers; b && b != po; b = b->next)
+	      for (b = all_buffers; b && b != po; b = b->header.next.buffer)
 		;
 	      if (b == NULL)
 		abort ();
@@ -5380,7 +5377,7 @@
 	   recursion there.  */
 	{
 	  register struct Lisp_Vector *ptr = XVECTOR (obj);
-	  register EMACS_UINT size = ptr->size;
+	  register EMACS_UINT size = ptr->header.size;
 	  register EMACS_UINT i;
 
 	  CHECK_LIVE (live_vector_p);
@@ -6012,10 +6009,10 @@
       if (!VECTOR_MARKED_P (buffer))
 	{
 	  if (prev)
-	    prev->next = buffer->next;
+	    prev->header.next = buffer->header.next;
 	  else
-	    all_buffers = buffer->next;
-	  next = buffer->next;
+	    all_buffers = buffer->header.next.buffer;
+	  next = buffer->header.next.buffer;
 	  lisp_free (buffer);
 	  buffer = next;
 	}
@@ -6023,7 +6020,7 @@
 	{
 	  VECTOR_UNMARK (buffer);
 	  UNMARK_BALANCE_INTERVALS (BUF_INTERVALS (buffer));
-	  prev = buffer, buffer = buffer->next;
+	  prev = buffer, buffer = buffer->header.next.buffer;
 	}
   }
 
@@ -6036,10 +6033,10 @@
       if (!VECTOR_MARKED_P (vector))
 	{
 	  if (prev)
-	    prev->next = vector->next;
+	    prev->header.next = vector->header.next;
 	  else
-	    all_vectors = vector->next;
-	  next = vector->next;
+	    all_vectors = vector->header.next.vector;
+	  next = vector->header.next.vector;
 	  lisp_free (vector);
 	  n_vectors--;
 	  vector = next;
@@ -6048,11 +6045,11 @@
       else
 	{
 	  VECTOR_UNMARK (vector);
-	  if (vector->size & PSEUDOVECTOR_FLAG)
-	    total_vector_size += (PSEUDOVECTOR_SIZE_MASK & vector->size);
+	  if (vector->header.size & PSEUDOVECTOR_FLAG)
+	    total_vector_size += PSEUDOVECTOR_SIZE_MASK & vector->header.size;
 	  else
-	    total_vector_size += vector->size;
-	  prev = vector, vector = vector->next;
+	    total_vector_size += vector->header.size;
+	  prev = vector, vector = vector->header.next.vector;
 	}
   }
 

=== modified file 'src/buffer.c'
--- src/buffer.c	2011-04-14 19:34:42 +0000
+++ src/buffer.c	2011-04-25 21:34:39 +0000
@@ -43,7 +43,7 @@
 struct buffer *current_buffer;		/* the current buffer */
 
 /* First buffer in chain of all buffers (in reverse order of creation).
-   Threaded through ->next.  */
+   Threaded through ->header.next.buffer.  */
 
 struct buffer *all_buffers;
 
@@ -359,7 +359,7 @@
   b->prevent_redisplay_optimizations_p = 1;
 
   /* Put this on the chain of all buffers including killed ones.  */
-  b->next = all_buffers;
+  b->header.next.buffer = all_buffers;
   all_buffers = b;
 
   /* An ordinary buffer normally doesn't need markers
@@ -588,7 +588,7 @@
   BVAR (b, width_table) = Qnil;
 
   /* Put this on the chain of all buffers including killed ones.  */
-  b->next = all_buffers;
+  b->header.next.buffer = all_buffers;
   all_buffers = b;
 
   name = Fcopy_sequence (name);
@@ -1458,7 +1458,7 @@
 
       GCPRO1 (buffer);
 
-      for (other = all_buffers; other; other = other->next)
+      for (other = all_buffers; other; other = other->header.next.buffer)
 	/* all_buffers contains dead buffers too;
 	   don't re-kill them.  */
 	if (other->base_buffer == b && !NILP (BVAR (other, name)))
@@ -2099,7 +2099,7 @@
 
   { /* This is probably harder to make work.  */
     struct buffer *other;
-    for (other = all_buffers; other; other = other->next)
+    for (other = all_buffers; other; other = other->header.next.buffer)
       if (other->base_buffer == other_buffer
 	  || other->base_buffer == current_buffer)
 	error ("One of the buffers to swap has indirect buffers");
@@ -2476,7 +2476,7 @@
 
   /* Copy this buffer's new multibyte status
      into all of its indirect buffers.  */
-  for (other = all_buffers; other; other = other->next)
+  for (other = all_buffers; other; other = other->header.next.buffer)
     if (other->base_buffer == current_buffer && !NILP (BVAR (other, name)))
       {
 	BVAR (other, enable_multibyte_characters)
@@ -4178,7 +4178,7 @@
 static void
 add_overlay_mod_hooklist (Lisp_Object functionlist, Lisp_Object overlay)
 {
-  int oldsize = XVECTOR (last_overlay_modification_hooks)->size;
+  int oldsize = ASIZE (last_overlay_modification_hooks);
 
   if (last_overlay_modification_hooks_used == oldsize)
     last_overlay_modification_hooks = larger_vector
@@ -4973,9 +4973,9 @@
   buffer_local_symbols.text = &buffer_local_symbols.own_text;
   BUF_INTERVALS (&buffer_defaults) = 0;
   BUF_INTERVALS (&buffer_local_symbols) = 0;
-  XSETPVECTYPE (&buffer_defaults, PVEC_BUFFER);
+  XSETPVECTYPESIZE (&buffer_defaults, PVEC_BUFFER, 0);
   XSETBUFFER (Vbuffer_defaults, &buffer_defaults);
-  XSETPVECTYPE (&buffer_local_symbols, PVEC_BUFFER);
+  XSETPVECTYPESIZE (&buffer_local_symbols, PVEC_BUFFER, 0);
   XSETBUFFER (Vbuffer_local_symbols, &buffer_local_symbols);
 
   /* Set up the default values of various buffer slots.  */

=== modified file 'src/buffer.h'
--- src/buffer.h	2011-04-11 01:41:15 +0000
+++ src/buffer.h	2011-04-25 19:40:22 +0000
@@ -499,14 +499,13 @@
 
      Check out mark_buffer (alloc.c) to see why.  */
 
-  EMACS_UINT size;
-
-  /* Next buffer, in chain of all buffers including killed buffers.
+  /* HEADER.NEXT is the next buffer, in chain of all buffers,
+     including killed buffers.
      This chain is used only for garbage collection, in order to
      collect killed buffers properly.
      Note that vectors and most pseudovectors are all on one chain,
      but buffers are on a separate chain of their own.  */
-  struct buffer *next;
+  struct vectorlike_header header;
 
   /* This structure holds the coordinates of the buffer contents
      in ordinary buffers.  In indirect buffers, this is not used.  */

=== modified file 'src/bytecode.c'
--- src/bytecode.c	2011-04-24 05:30:24 +0000
+++ src/bytecode.c	2011-04-25 21:34:39 +0000
@@ -467,7 +467,7 @@
   CHECK_NUMBER (maxdepth);
 
 #ifdef BYTE_CODE_SAFE
-  const_length = XVECTOR (vector)->size;
+  const_length = ASIZE (vector);
 #endif
 
   if (STRING_MULTIBYTE (bytestr))

=== modified file 'src/callint.c'
--- src/callint.c	2011-04-14 05:04:02 +0000
+++ src/callint.c	2011-04-25 21:34:39 +0000
@@ -293,7 +293,7 @@
   else
     {
       CHECK_VECTOR (keys);
-      key_count = XVECTOR (keys)->size;
+      key_count = ASIZE (keys);
     }
 
   /* Save this now, since use of minibuffer will clobber it. */

=== modified file 'src/ccl.c'
--- src/ccl.c	2011-04-14 05:04:02 +0000
+++ src/ccl.c	2011-04-25 07:14:46 +0000
@@ -1903,7 +1903,7 @@
       if (! VECTORP (ccl_prog))
 	return -1;
       vp = XVECTOR (ccl_prog);
-      ccl->size = vp->size;
+      ccl->size = vp->header.size;
       ccl->prog = vp->contents;
       ccl->eof_ic = XINT (vp->contents[CCL_HEADER_EOF]);
       ccl->buf_magnification = XINT (vp->contents[CCL_HEADER_BUF_MAG]);

=== modified file 'src/character.c'
--- src/character.c	2011-04-14 05:04:02 +0000
+++ src/character.c	2011-04-25 21:34:39 +0000
@@ -357,7 +357,7 @@
 	{
 	  val = DISP_CHAR_VECTOR (dp, c);
 	  if (VECTORP (val))
-	    thiswidth = XVECTOR (val)->size;
+	    thiswidth = ASIZE (val);
 	  else
 	    thiswidth = CHAR_WIDTH (c);
 	}
@@ -446,7 +446,7 @@
 	    {
 	      val = DISP_CHAR_VECTOR (dp, c);
 	      if (VECTORP (val))
-		thiswidth = XVECTOR (val)->size;
+		thiswidth = ASIZE (val);
 	      else
 		thiswidth = CHAR_WIDTH (c);
 	    }

=== modified file 'src/chartab.c'
--- src/chartab.c	2011-04-14 05:04:02 +0000
+++ src/chartab.c	2011-04-25 07:14:46 +0000
@@ -146,7 +146,7 @@
 copy_char_table (Lisp_Object table)
 {
   Lisp_Object copy;
-  int size = XCHAR_TABLE (table)->size & PSEUDOVECTOR_SIZE_MASK;
+  int size = XCHAR_TABLE (table)->header.size & PSEUDOVECTOR_SIZE_MASK;
   int i;
 
   copy = Fmake_vector (make_number (size), Qnil);

=== modified file 'src/coding.c'
--- src/coding.c	2011-04-19 00:34:42 +0000
+++ src/coding.c	2011-04-25 21:34:39 +0000
@@ -7125,7 +7125,7 @@
 	      components = COMPOSITION_COMPONENTS (prop);
 	      if (VECTORP (components))
 		{
-		  len = XVECTOR (components)->size;
+		  len = ASIZE (components);
 		  for (i = 0; i < len; i++)
 		    *buf++ = XINT (AREF (components, i));
 		}

=== modified file 'src/composite.c'
--- src/composite.c	2011-04-14 19:34:42 +0000
+++ src/composite.c	2011-04-25 21:34:39 +0000
@@ -293,7 +293,7 @@
     }
   else if (VECTORP (components) || CONSP (components))
     {
-      EMACS_UINT len = XVECTOR (key)->size;
+      EMACS_UINT len = ASIZE (key);
 
       /* The number of elements should be odd.  */
       if ((len % 2) == 0)
@@ -326,8 +326,8 @@
 		    : COMPOSITION_WITH_RULE_ALTCHARS));
   cmp->hash_index = hash_index;
   glyph_len = (cmp->method == COMPOSITION_WITH_RULE_ALTCHARS
-	       ? (XVECTOR (key)->size + 1) / 2
-	       : XVECTOR (key)->size);
+	       ? (ASIZE (key) + 1) / 2
+	       : ASIZE (key));
   cmp->glyph_len = glyph_len;
   cmp->offsets = (short *) xmalloc (sizeof (short) * glyph_len * 2);
   cmp->font = NULL;

=== modified file 'src/data.c'
--- src/data.c	2011-04-21 06:03:09 +0000
+++ src/data.c	2011-04-25 21:34:39 +0000
@@ -1389,7 +1389,7 @@
 	      {
 		struct buffer *b;
 
-		for (b = all_buffers; b; b = b->next)
+		for (b = all_buffers; b; b = b->header.next.buffer)
 		  if (!PER_BUFFER_VALUE_P (b, idx))
 		    PER_BUFFER_VALUE (b, offset) = value;
 	      }
@@ -2093,9 +2093,9 @@
     {
       int size = 0;
       if (VECTORP (array))
-	size = XVECTOR (array)->size;
+	size = ASIZE (array);
       else if (COMPILEDP (array))
-	size = XVECTOR (array)->size & PSEUDOVECTOR_SIZE_MASK;
+	size = ASIZE (array) & PSEUDOVECTOR_SIZE_MASK;
       else
 	wrong_type_argument (Qarrayp, array);
 
@@ -2120,7 +2120,7 @@
 
   if (VECTORP (array))
     {
-      if (idxval < 0 || idxval >= XVECTOR (array)->size)
+      if (idxval < 0 || idxval >= ASIZE (array))
 	args_out_of_range (array, idx);
       XVECTOR (array)->contents[idxval] = newelt;
     }

=== modified file 'src/dispnew.c'
--- src/dispnew.c	2011-04-14 05:04:02 +0000
+++ src/dispnew.c	2011-04-25 21:34:39 +0000
@@ -6073,7 +6073,7 @@
     state = frame_and_buffer_state;
 
   vecp = XVECTOR (state)->contents;
-  end = vecp + XVECTOR (state)->size;
+  end = vecp + ASIZE (state);
 
   FOR_EACH_FRAME (tail, frame)
     {
@@ -6124,8 +6124,8 @@
   /* Reallocate the vector if data has grown to need it,
      or if it has shrunk a lot.  */
   if (! VECTORP (state)
-      || n > XVECTOR (state)->size
-      || n + 20 < XVECTOR (state)->size / 2)
+      || n > ASIZE (state)
+      || n + 20 < ASIZE (state) / 2)
     /* Add 20 extra so we grow it less often.  */
     {
       state = Fmake_vector (make_number (n + 20), Qlambda);
@@ -6155,11 +6155,11 @@
   /* Fill up the vector with lambdas (always at least one).  */
   *vecp++ = Qlambda;
   while (vecp - XVECTOR (state)->contents
-	 < XVECTOR (state)->size)
+	 < ASIZE (state))
     *vecp++ = Qlambda;
   /* Make sure we didn't overflow the vector.  */
   if (vecp - XVECTOR (state)->contents
-      > XVECTOR (state)->size)
+      > ASIZE (state))
     abort ();
   return Qt;
 }

=== modified file 'src/disptab.h'
--- src/disptab.h	2011-01-25 04:08:28 +0000
+++ src/disptab.h	2011-04-25 21:34:39 +0000
@@ -54,7 +54,7 @@
 /* Return the current length of the GLYPH table,
    or 0 if the table isn't currently valid.  */
 #define GLYPH_TABLE_LENGTH  \
-  ((VECTORP (Vglyph_table)) ? XVECTOR (Vglyph_table)->size : 0)
+  ((VECTORP (Vglyph_table)) ? ASIZE (Vglyph_table) : 0)
 
 /* Return the current base (for indexing) of the GLYPH table,
    or 0 if the table isn't currently valid.  */
@@ -95,4 +95,3 @@
 
 #define SET_GLYPH_FROM_CHAR(glyph, c) \
   SET_GLYPH (glyph, c, DEFAULT_FACE_ID)
-

=== modified file 'src/doc.c'
--- src/doc.c	2011-04-19 00:34:42 +0000
+++ src/doc.c	2011-04-25 21:34:39 +0000
@@ -787,7 +787,7 @@
 	do_remap:
 	  tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil);
 
-	  if (VECTORP (tem) && XVECTOR (tem)->size > 1
+	  if (VECTORP (tem) && ASIZE (tem) > 1
 	      && EQ (AREF (tem, 0), Qremap) && SYMBOLP (AREF (tem, 1))
 	      && follow_remap)
 	    {

=== modified file 'src/fns.c'
--- src/fns.c	2011-04-19 01:11:43 +0000
+++ src/fns.c	2011-04-25 07:14:46 +0000
@@ -3681,9 +3681,9 @@
   struct Lisp_Vector *next;
 
   h2 = allocate_hash_table ();
-  next = h2->vec_next;
+  next = h2->header.next.vector;
   memcpy (h2, h1, sizeof *h2);
-  h2->vec_next = next;
+  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);
@@ -4026,7 +4026,7 @@
       marked = 0;
       for (h = weak_hash_tables; h; h = h->next_weak)
 	{
-	  if (h->size & ARRAY_MARK_FLAG)
+	  if (h->header.size & ARRAY_MARK_FLAG)
 	    marked |= sweep_weak_table (h, 0);
 	}
     }
@@ -4037,7 +4037,7 @@
     {
       next = h->next_weak;
 
-      if (h->size & ARRAY_MARK_FLAG)
+      if (h->header.size & ARRAY_MARK_FLAG)
 	{
 	  /* TABLE is marked as used.  Sweep its contents.  */
 	  if (h->count > 0)
@@ -4153,7 +4153,7 @@
   unsigned hash = XBOOL_VECTOR (vec)->size;
   int i, n;
 
-  n = min (SXHASH_MAX_LEN, XBOOL_VECTOR (vec)->vector_size);
+  n = min (SXHASH_MAX_LEN, XBOOL_VECTOR (vec)->header.size);
   for (i = 0; i < n; ++i)
     hash = SXHASH_COMBINE (hash, XBOOL_VECTOR (vec)->data[i]);
 

=== modified file 'src/font.c'
--- src/font.c	2011-04-19 00:34:42 +0000
+++ src/font.c	2011-04-25 21:34:39 +0000
@@ -253,7 +253,7 @@
   /* The following code is copied from the function intern (in
      lread.c), and modified to suite our purpose.  */
   obarray = Vobarray;
-  if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
+  if (!VECTORP (obarray) || ASIZE (obarray) == 0)
     obarray = check_obarray (obarray);
   parse_str_as_multibyte ((unsigned char *) str, len, &nchars, &nbytes);
   if (len == nchars || len != nbytes)

=== modified file 'src/font.h'
--- src/font.h	2011-04-13 23:22:35 +0000
+++ src/font.h	2011-04-25 19:40:22 +0000
@@ -254,8 +254,7 @@
 
 struct font_spec
 {
-  EMACS_UINT size;
-  struct Lisp_Vector *next;
+  struct vectorlike_header header;
   Lisp_Object props[FONT_SPEC_MAX];
 };
 
@@ -263,8 +262,7 @@
 
 struct font_entity
 {
-  EMACS_UINT size;
-  struct Lisp_Vector *next;
+  struct vectorlike_header header;
   Lisp_Object props[FONT_ENTITY_MAX];
 };
 
@@ -277,8 +275,7 @@
 
 struct font
 {
-  EMACS_UINT size;
-  struct Lisp_Vector *next;
+  struct vectorlike_header header;
 
   /* All Lisp_Object components must come first.
      That ensures they are all aligned normally.  */

=== modified file 'src/frame.h'
--- src/frame.h	2011-04-16 08:36:41 +0000
+++ src/frame.h	2011-04-25 19:40:22 +0000
@@ -82,8 +82,7 @@
 
 struct frame
 {
-  EMACS_UINT size;
-  struct Lisp_Vector *next;
+  struct vectorlike_header header;
 
   /* All Lisp_Object components must come first.
      That ensures they are all aligned normally.  */

=== modified file 'src/fringe.c'
--- src/fringe.c	2011-04-13 23:38:13 +0000
+++ src/fringe.c	2011-04-25 21:34:39 +0000
@@ -1531,7 +1531,7 @@
   if (STRINGP (bits))
     h = SCHARS (bits);
   else if (VECTORP (bits))
-    h = XVECTOR (bits)->size;
+    h = ASIZE (bits);
   else
     wrong_type_argument (Qsequencep, bits);
 

=== modified file 'src/image.c'
--- src/image.c	2011-04-14 19:34:42 +0000
+++ src/image.c	2011-04-25 21:34:39 +0000
@@ -2359,7 +2359,7 @@
 	  int i;
 
 	  /* Number of elements of the vector must be >= height.  */
-	  if (XVECTOR (data)->size < height)
+	  if (ASIZE (data) < height)
 	    return 0;
 
 	  /* Each string or bool-vector in data must be large enough
@@ -8398,7 +8398,7 @@
     }
   else if (VECTORP (tem))
     {
-      if (XVECTOR (tem)->size != 4)
+      if (ASIZE (tem) != 4)
 	return 0;
       for (i = 0; i < 4; ++i)
 	if (!INTEGERP (XVECTOR (tem)->contents[i]))

=== modified file 'src/indent.c'
--- src/indent.c	2011-04-16 18:26:30 +0000
+++ src/indent.c	2011-04-25 21:34:39 +0000
@@ -93,7 +93,7 @@
   /* Everything can be handled by the display table, if it's
      present and the element is right.  */
   if (dp && (elt = DISP_CHAR_VECTOR (dp, c), VECTORP (elt)))
-    return XVECTOR (elt)->size;
+    return ASIZE (elt);
 
   /* Some characters are special.  */
   if (c == '\n' || c == '\t' || c == '\015')
@@ -121,7 +121,7 @@
 {
   int i;
 
-  if (widthtab->size != 256)
+  if (widthtab->header.size != 256)
     abort ();
 
   for (i = 0; i < 256; i++)
@@ -143,7 +143,7 @@
   if (!VECTORP (BVAR (buf, width_table)))
     BVAR (buf, width_table) = Fmake_vector (make_number (256), make_number (0));
   widthtab = XVECTOR (BVAR (buf, width_table));
-  if (widthtab->size != 256)
+  if (widthtab->header.size != 256)
     abort ();
 
   for (i = 0; i < 256; i++)
@@ -284,7 +284,7 @@
     else								\
       {									\
 	if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, ch)))		\
-	  width = XVECTOR (DISP_CHAR_VECTOR (dp, ch))->size;		\
+	  width = ASIZE (DISP_CHAR_VECTOR (dp, ch));			\
 	else								\
 	  width = CHAR_WIDTH (ch);					\
       }									\
@@ -766,7 +766,7 @@
 
       c = *--ptr;
       if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
-	col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
+	col += ASIZE (DISP_CHAR_VECTOR (dp, c));
       else if (c >= 040 && c < 0177)
 	col++;
       else if (c == '\n')
@@ -1127,7 +1127,7 @@
        : !NILP (BVAR (current_buffer, selective_display)) ? -1 : 0);
   int selective_rlen
     = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
-       ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
+       ? ASIZE (DISP_INVIS_VECTOR (dp)) : 0);
   /* The next location where the `invisible' property changes, or an
      overlay starts or ends.  */
   EMACS_INT next_boundary = from;

=== modified file 'src/keyboard.c'
--- src/keyboard.c	2011-04-19 00:34:42 +0000
+++ src/keyboard.c	2011-04-25 21:34:39 +0000
@@ -134,7 +134,7 @@
 static int raw_keybuf_count;
 
 #define GROW_RAW_KEYBUF							\
- if (raw_keybuf_count == XVECTOR (raw_keybuf)->size)			\
+ if (raw_keybuf_count == ASIZE (raw_keybuf))				\
    raw_keybuf = larger_vector (raw_keybuf, raw_keybuf_count * 2, Qnil)  \
 
 /* Number of elements of this_command_keys
@@ -2898,7 +2898,7 @@
       if ((STRINGP (KVAR (current_kboard, Vkeyboard_translate_table))
 	   && SCHARS (KVAR (current_kboard, Vkeyboard_translate_table)) > (unsigned) XFASTINT (c))
 	  || (VECTORP (KVAR (current_kboard, Vkeyboard_translate_table))
-	      && XVECTOR (KVAR (current_kboard, Vkeyboard_translate_table))->size > (unsigned) XFASTINT (c))
+	      && ASIZE (KVAR (current_kboard, Vkeyboard_translate_table)) > (unsigned) XFASTINT (c))
 	  || (CHAR_TABLE_P (KVAR (current_kboard, Vkeyboard_translate_table))
 	      && CHARACTERP (c)))
 	{
@@ -4198,7 +4198,7 @@
 
       timer = XCAR (timers);
 
-      if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+      if (!VECTORP (timer) || ASIZE (timer) != 8)
 	continue;
       XVECTOR (timer)->contents[0] = Qnil;
     }
@@ -4293,7 +4293,7 @@
       if (CONSP (timers))
 	{
 	  timer = XCAR (timers);
-	  if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+	  if (!VECTORP (timer) || ASIZE (timer) != 8)
 	    {
 	      timers = XCDR (timers);
 	      continue;
@@ -4311,7 +4311,7 @@
       if (CONSP (idle_timers))
 	{
 	  timer = XCAR (idle_timers);
-	  if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+	  if (!VECTORP (timer) || ASIZE (timer) != 8)
 	    {
 	      idle_timers = XCDR (idle_timers);
 	      continue;
@@ -5459,7 +5459,7 @@
 		/* Find the menu bar item under `column'.  */
 		item = Qnil;
 		items = FRAME_MENU_BAR_ITEMS (f);
-		for (i = 0; i < XVECTOR (items)->size; i += 4)
+		for (i = 0; i < ASIZE (items); i += 4)
 		  {
 		    Lisp_Object pos, string;
 		    string = AREF (items, i + 1);
@@ -5652,7 +5652,7 @@
 				      Qmouse_click, Vlispy_mouse_stem,
 				      NULL,
 				      &mouse_syms,
-				      XVECTOR (mouse_syms)->size);
+				      ASIZE (mouse_syms));
 	  if (event->modifiers & drag_modifier)
 	    return Fcons (head,
 			  Fcons (start_pos,
@@ -5823,7 +5823,7 @@
 				    Qmouse_click,
 				    Vlispy_mouse_stem,
 				    NULL, &mouse_syms,
-				    XVECTOR (mouse_syms)->size);
+				    ASIZE (mouse_syms));
 	return Fcons (head, Fcons (position, Qnil));
       }
 
@@ -5943,7 +5943,7 @@
 				    Qmouse_click, Vlispy_mouse_stem,
 				    NULL,
 				    &mouse_syms,
-				    XVECTOR (mouse_syms)->size);
+				    ASIZE (mouse_syms));
 
 	if (event->modifiers & drag_modifier)
 	  return Fcons (head,
@@ -6422,7 +6422,7 @@
   else
     {
       if (! VECTORP (*symbol_table)
-	  || XVECTOR (*symbol_table)->size != table_size)
+	  || ASIZE (*symbol_table) != table_size)
 	{
 	  Lisp_Object size;
 
@@ -7479,7 +7479,7 @@
   /* Add nil, nil, nil, nil at the end.  */
   {
     int i = menu_bar_items_index;
-    if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
+    if (i + 4 > ASIZE (menu_bar_items_vector))
       menu_bar_items_vector =
 	larger_vector (menu_bar_items_vector, 2 * i, Qnil);
     /* Add this item.  */
@@ -7551,7 +7551,7 @@
   if (i == menu_bar_items_index)
     {
       /* If vector is too small, get a bigger one.  */
-      if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
+      if (i + 4 > ASIZE (menu_bar_items_vector))
 	menu_bar_items_vector = larger_vector (menu_bar_items_vector, 2 * i, Qnil);
       /* Add this item.  */
       XVECTOR (menu_bar_items_vector)->contents[i++] = key;
@@ -8219,7 +8219,7 @@
 	}
       else if (EQ (ikey, QCimage)
 	       && (CONSP (value)
-		   || (VECTORP (value) && XVECTOR (value)->size == 4)))
+		   || (VECTORP (value) && ASIZE (value) == 4)))
 	/* Value is either a single image specification or a vector
 	   of 4 such specifications for the different button states.  */
 	PROP (TOOL_BAR_ITEM_IMAGES) = value;
@@ -8323,10 +8323,10 @@
 
   /* Enlarge tool_bar_items_vector if necessary.  */
   if (ntool_bar_items + TOOL_BAR_ITEM_NSLOTS
-      >= XVECTOR (tool_bar_items_vector)->size)
+      >= ASIZE (tool_bar_items_vector))
     tool_bar_items_vector
       = larger_vector (tool_bar_items_vector,
-		       2 * XVECTOR (tool_bar_items_vector)->size, Qnil);
+		       2 * ASIZE (tool_bar_items_vector), Qnil);
 
   /* Append entries from tool_bar_item_properties to the end of
      tool_bar_items_vector.  */
@@ -8648,7 +8648,7 @@
 		}
 
 	      /* Move past this element.  */
-	      if (idx >= 0 && idx + 1 >= XVECTOR (vector)->size)
+	      if (idx >= 0 && idx + 1 >= ASIZE (vector))
 		/* Handle reaching end of dense table.  */
 		idx = -1;
 	      if (idx >= 0)
@@ -9926,7 +9926,7 @@
 	      /* Treat uppercase keys as shifted.  */
 	      || (INTEGERP (key)
 		  && (KEY_TO_CHAR (key)
-		      < XCHAR_TABLE (BVAR (current_buffer, downcase_table))->size)
+		      < XCHAR_TABLE (BVAR (current_buffer, downcase_table))->header.size)
 		  && uppercasep (KEY_TO_CHAR (key))))
 	    {
 	      Lisp_Object new_key
@@ -10292,7 +10292,7 @@
     this_single_command_key_start = 0;
 
     keys = XVECTOR (saved_keys)->contents;
-    for (i = 0; i < XVECTOR (saved_keys)->size; i++)
+    for (i = 0; i < ASIZE (saved_keys); i++)
       add_command_key (keys[i]);
 
     for (i = 0; i < SCHARS (function); i++)
@@ -10585,7 +10585,7 @@
 
   if (NILP (keep_record))
     {
-      for (i = 0; i < XVECTOR (recent_keys)->size; ++i)
+      for (i = 0; i < ASIZE (recent_keys); ++i)
 	XVECTOR (recent_keys)->contents[i] = Qnil;
       total_keys = 0;
       recent_keys_index = 0;

=== modified file 'src/keymap.c'
--- src/keymap.c	2011-04-14 19:34:42 +0000
+++ src/keymap.c	2011-04-25 21:34:39 +0000
@@ -359,7 +359,7 @@
 				XCDR (XCAR (list)));
 
       if (VECTORP (XCAR (list)))
-	for (i = 0; i < XVECTOR (XCAR (list))->size; i++)
+	for (i = 0; i < ASIZE (XCAR (list)); i++)
 	  if (CONSP (XVECTOR (XCAR (list))->contents[i]))
 	    fix_submap_inheritance (keymap, make_number (i),
 				    XVECTOR (XCAR (list))->contents[i]);
@@ -2226,7 +2226,7 @@
   if (STRINGP (list))
     size = SCHARS (list);
   else if (VECTORP (list))
-    size = XVECTOR (list)->size;
+    size = ASIZE (list);
   else if (CONSP (list))
     size = XINT (Flength (list));
   else
@@ -3125,7 +3125,7 @@
 
 	  elt = XCAR (list);
 	  elt_prefix = Fcar (elt);
-	  if (XVECTOR (elt_prefix)->size >= 1)
+	  if (ASIZE (elt_prefix) >= 1)
 	    {
 	      tem = Faref (elt_prefix, make_number (0));
 	      if (EQ (tem, Qmenu_bar))
@@ -3168,7 +3168,7 @@
 	  /* If the sequence by which we reach this keymap is zero-length,
 	     then the shadow map for this keymap is just SHADOW.  */
 	  if ((STRINGP (elt_prefix) && SCHARS (elt_prefix) == 0)
-	      || (VECTORP (elt_prefix) && XVECTOR (elt_prefix)->size == 0))
+	      || (VECTORP (elt_prefix) && ASIZE (elt_prefix) == 0))
 	    ;
 	  /* If the sequence by which we reach this keymap actually has
 	     some elements, then the sequence's definition in SHADOW is
@@ -3592,7 +3592,7 @@
   if (CHAR_TABLE_P (vector))
     stop = MAX_5_BYTE_CHAR + 1, to = MAX_CHAR + 1;
   else
-    stop = to = XVECTOR (vector)->size;
+    stop = to = ASIZE (vector);
 
   for (i = from; ; i++)
     {

=== modified file 'src/lread.c'
--- src/lread.c	2011-04-21 19:15:37 +0000
+++ src/lread.c	2011-04-25 21:34:39 +0000
@@ -2430,7 +2430,7 @@
 	    {
 	      Lisp_Object tmp;
 	      tmp = read_vector (readcharfun, 0);
-	      if (XVECTOR (tmp)->size < CHAR_TABLE_STANDARD_SLOTS)
+	      if (ASIZE (tmp) < CHAR_TABLE_STANDARD_SLOTS)
 		error ("Invalid size char-table");
 	      XSETPVECTYPE (XVECTOR (tmp), PVEC_CHAR_TABLE);
 	      return tmp;
@@ -2449,7 +2449,7 @@
 		  depth = XINT (AREF (tmp, 0));
 		  if (depth < 1 || depth > 3)
 		    error ("Invalid depth in char-table");
-		  size = XVECTOR (tmp)->size - 2;
+		  size = ASIZE (tmp) - 2;
 		  if (chartab_size [depth] != size)
 		    error ("Invalid size char-table");
 		  XSETPVECTYPE (XVECTOR (tmp), PVEC_SUB_CHAR_TABLE);
@@ -2499,7 +2499,7 @@
 	     build them using function calls.  */
 	  Lisp_Object tmp;
 	  tmp = read_vector (readcharfun, 1);
-	  return Fmake_byte_code (XVECTOR (tmp)->size,
+	  return Fmake_byte_code (ASIZE (tmp),
 				  XVECTOR (tmp)->contents);
 	}
       if (c == '(')
@@ -3356,7 +3356,7 @@
   len = Flength (tem);
   vector = (read_pure ? make_pure_vector (XINT (len)) : Fmake_vector (len, Qnil));
 
-  size = XVECTOR (vector)->size;
+  size = ASIZE (vector);
   ptr = XVECTOR (vector)->contents;
   for (i = 0; i < size; i++)
     {
@@ -3621,7 +3621,7 @@
 Lisp_Object
 check_obarray (Lisp_Object obarray)
 {
-  if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
+  if (!VECTORP (obarray) || ASIZE (obarray) == 0)
     {
       /* If Vobarray is now invalid, force it to be valid.  */
       if (EQ (Vobarray, obarray)) Vobarray = initial_obarray;
@@ -3641,7 +3641,7 @@
   Lisp_Object obarray;
 
   obarray = Vobarray;
-  if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
+  if (!VECTORP (obarray) || ASIZE (obarray) == 0)
     obarray = check_obarray (obarray);
   tem = oblookup (obarray, str, len, len);
   if (SYMBOLP (tem))
@@ -3657,7 +3657,7 @@
   Lisp_Object obarray;
 
   obarray = Vobarray;
-  if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
+  if (!VECTORP (obarray) || ASIZE (obarray) == 0)
     obarray = check_obarray (obarray);
   tem = oblookup (obarray, str, len, len);
   if (SYMBOLP (tem))
@@ -3830,10 +3830,10 @@
   Lisp_Object bucket, tem;
 
   if (!VECTORP (obarray)
-      || (obsize = XVECTOR (obarray)->size) == 0)
+      || (obsize = ASIZE (obarray)) == 0)
     {
       obarray = check_obarray (obarray);
-      obsize = XVECTOR (obarray)->size;
+      obsize = ASIZE (obarray);
     }
   /* This is sometimes needed in the middle of GC.  */
   obsize &= ~ARRAY_MARK_FLAG;
@@ -3881,7 +3881,7 @@
   register int i;
   register Lisp_Object tail;
   CHECK_VECTOR (obarray);
-  for (i = XVECTOR (obarray)->size - 1; i >= 0; i--)
+  for (i = ASIZE (obarray) - 1; i >= 0; i--)
     {
       tail = XVECTOR (obarray)->contents[i];
       if (SYMBOLP (tail))
@@ -3961,7 +3961,7 @@
 {
   Lisp_Object sym;
   sym = intern_c_string (sname->symbol_name);
-  XSETPVECTYPE (sname, PVEC_SUBR);
+  XSETTYPED_PVECTYPE (sname, size, PVEC_SUBR);
   XSETSUBR (XSYMBOL (sym)->function, sname);
 }
 

=== modified file 'src/minibuf.c'
--- src/minibuf.c	2011-04-14 05:04:02 +0000
+++ src/minibuf.c	2011-04-25 21:34:39 +0000
@@ -1227,7 +1227,7 @@
   if (type == obarray_table)
     {
       collection = check_obarray (collection);
-      obsize = XVECTOR (collection)->size;
+      obsize = ASIZE (collection);
       bucket = XVECTOR (collection)->contents[idx];
     }
 
@@ -1490,7 +1490,7 @@
   if (type == 2)
     {
       collection = check_obarray (collection);
-      obsize = XVECTOR (collection)->size;
+      obsize = ASIZE (collection);
       bucket = XVECTOR (collection)->contents[idx];
     }
 
@@ -1804,7 +1804,7 @@
 
       if (completion_ignore_case && !SYMBOLP (tem))
 	{
-	  for (i = XVECTOR (collection)->size - 1; i >= 0; i--)
+	  for (i = ASIZE (collection) - 1; i >= 0; i--)
 	    {
 	      tail = XVECTOR (collection)->contents[i];
 	      if (SYMBOLP (tail))

=== modified file 'src/print.c'
--- src/print.c	2011-04-19 06:52:00 +0000
+++ src/print.c	2011-04-25 21:34:39 +0000
@@ -1198,7 +1198,7 @@
 	  goto loop;
 
 	case Lisp_Vectorlike:
-	  size = XVECTOR (obj)->size;
+	  size = ASIZE (obj);
 	  if (size & PSEUDOVECTOR_FLAG)
 	    size &= PSEUDOVECTOR_SIZE_MASK;
 	  for (i = 0; i < size; i++)
@@ -1786,7 +1786,7 @@
 	      strout (SDATA (SYMBOL_NAME (h->weak)), -1, -1, printcharfun);
 	      PRINTCHAR (' ');
 	      sprintf (buf, "%ld/%ld", (long) h->count,
-		       (long) XVECTOR (h->next)->size);
+		       (long) ASIZE (h->next));
 	      strout (buf, -1, -1, printcharfun);
 	    }
 	  sprintf (buf, " 0x%lx", (unsigned long) h);
@@ -1797,7 +1797,7 @@
 	    #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
 	  /* Always print the size. */
 	  sprintf (buf, "#s(hash-table size %ld",
-		   (long) XVECTOR (h->next)->size);
+		   (long) ASIZE (h->next));
 	  strout (buf, -1, -1, printcharfun);
 
 	  if (!NILP (h->test))
@@ -1909,7 +1909,7 @@
 	}
       else
 	{
-	  EMACS_INT size = XVECTOR (obj)->size;
+	  EMACS_INT size = ASIZE (obj);
 	  if (COMPILEDP (obj))
 	    {
 	      PRINTCHAR ('#');
@@ -2025,7 +2025,7 @@
 	if (MISCP (obj))
 	  sprintf (buf, "(MISC 0x%04x)", (int) XMISCTYPE (obj));
 	else if (VECTORLIKEP (obj))
-	  sprintf (buf, "(PVEC 0x%08lx)", (unsigned long) XVECTOR (obj)->size);
+	  sprintf (buf, "(PVEC 0x%08lx)", (unsigned long) ASIZE (obj));
 	else
 	  sprintf (buf, "(0x%02x)", (int) XTYPE (obj));
 	strout (buf, -1, -1, printcharfun);

=== modified file 'src/process.c'
--- src/process.c	2011-04-19 06:42:12 +0000
+++ src/process.c	2011-04-25 07:14:46 +0000
@@ -1188,25 +1188,26 @@
   if (VECTORP (address))  /* AF_INET or AF_INET6 */
     {
       register struct Lisp_Vector *p = XVECTOR (address);
+      EMACS_UINT size = p->header.size;
       Lisp_Object args[10];
       int nargs, i;
 
-      if (p->size == 4 || (p->size == 5 && !NILP (omit_port)))
+      if (size == 4 || (size == 5 && !NILP (omit_port)))
 	{
 	  args[0] = build_string ("%d.%d.%d.%d");
 	  nargs = 4;
 	}
-      else if (p->size == 5)
+      else if (size == 5)
 	{
 	  args[0] = build_string ("%d.%d.%d.%d:%d");
 	  nargs = 5;
 	}
-      else if (p->size == 8 || (p->size == 9 && !NILP (omit_port)))
+      else if (size == 8 || (size == 9 && !NILP (omit_port)))
 	{
 	  args[0] = build_string ("%x:%x:%x:%x:%x:%x:%x:%x");
 	  nargs = 8;
 	}
-      else if (p->size == 9)
+      else if (size == 9)
 	{
 	  args[0] = build_string ("[%x:%x:%x:%x:%x:%x:%x:%x]:%d");
 	  nargs = 9;
@@ -2064,13 +2065,13 @@
   if (VECTORP (address))
     {
       p = XVECTOR (address);
-      if (p->size == 5)
+      if (p->header.size == 5)
 	{
 	  *familyp = AF_INET;
 	  return sizeof (struct sockaddr_in);
 	}
 #ifdef AF_INET6
-      else if (p->size == 9)
+      else if (p->header.size == 9)
 	{
 	  *familyp = AF_INET6;
 	  return sizeof (struct sockaddr_in6);
@@ -2089,7 +2090,7 @@
       struct sockaddr *sa;
       *familyp = XINT (XCAR (address));
       p = XVECTOR (XCDR (address));
-      return p->size + sizeof (sa->sa_family);
+      return p->header.size + sizeof (sa->sa_family);
     }
   return 0;
 }

=== modified file 'src/process.h'
--- src/process.h	2011-04-14 02:16:00 +0000
+++ src/process.h	2011-04-25 19:40:22 +0000
@@ -29,13 +29,13 @@
 /* This structure records information about a subprocess
    or network connection.
 
-   Every field in this structure except for the first two
+   Every field in this structure except for the header
    must be a Lisp_Object, for GC's sake.  */
 
 struct Lisp_Process
   {
-    EMACS_UINT size;
-    struct Lisp_Vector *v_next;
+    struct vectorlike_header header;
+
     /* Name of subprocess terminal.  */
     Lisp_Object tty_name;
     /* Name of this process */

=== modified file 'src/syntax.c'
--- src/syntax.c	2011-04-16 18:26:30 +0000
+++ src/syntax.c	2011-04-25 21:34:39 +0000
@@ -979,7 +979,7 @@
 	break;
       }
 
-  if (val < XVECTOR (Vsyntax_code_object)->size && NILP (match))
+  if (val < ASIZE (Vsyntax_code_object) && NILP (match))
     return XVECTOR (Vsyntax_code_object)->contents[val];
   else
     /* Since we can't use a shared object, let's make a new one.  */
@@ -3370,7 +3370,7 @@
 
   /* Create objects which can be shared among syntax tables.  */
   Vsyntax_code_object = Fmake_vector (make_number (Smax), Qnil);
-  for (i = 0; i < XVECTOR (Vsyntax_code_object)->size; i++)
+  for (i = 0; i < ASIZE (Vsyntax_code_object); i++)
     XVECTOR (Vsyntax_code_object)->contents[i]
       = Fcons (make_number (i), Qnil);
 

=== modified file 'src/termhooks.h'
--- src/termhooks.h	2011-04-17 18:40:55 +0000
+++ src/termhooks.h	2011-04-25 19:40:22 +0000
@@ -322,10 +322,8 @@
 /* Terminal-local parameters. */
 struct terminal
 {
-  /* The first two fields are really the header of a vector */
-  /* The terminal code does not refer to them.  */
-  EMACS_UINT size;
-  struct Lisp_Vector *vec_next;
+  /* This is for Lisp; the terminal code does not refer to it.  */
+  struct vectorlike_header header;
 
   /* Parameter alist of this terminal.  */
   Lisp_Object param_alist;

=== modified file 'src/w32font.c'
--- src/w32font.c	2011-03-23 16:25:38 +0000
+++ src/w32font.c	2011-04-25 21:34:39 +0000
@@ -165,7 +165,7 @@
 
   /* The following code is copied from the function intern (in lread.c).  */
   obarray = Vobarray;
-  if (!VECTORP (obarray) || XVECTOR (obarray)->size == 0)
+  if (!VECTORP (obarray) || ASIZE (obarray) == 0)
     obarray = check_obarray (obarray);
   tem = oblookup (obarray, SDATA (str), len, len);
   if (SYMBOLP (tem))
@@ -2581,4 +2581,3 @@
   w32font_driver.type = Qgdi;
   register_font_driver (&w32font_driver, NULL);
 }
-

=== modified file 'src/w32menu.c'
--- src/w32menu.c	2011-03-26 01:23:15 +0000
+++ src/w32menu.c	2011-04-25 21:34:39 +0000
@@ -427,11 +427,11 @@
 
       menu_items = f->menu_bar_vector;
       menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
-      submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
-      submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
-      submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
+      submenu_start = (int *) alloca (ASIZE (items) * sizeof (int *));
+      submenu_end = (int *) alloca (ASIZE (items) * sizeof (int *));
+      submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int));
       submenu_top_level_items
-	= (int *) alloca (XVECTOR (items)->size * sizeof (int *));
+	= (int *) alloca (ASIZE (items) * sizeof (int *));
       init_menu_items ();
       for (i = 0; i < ASIZE (items); i += 4)
 	{

=== modified file 'src/window.c'
--- src/window.c	2011-04-14 19:34:42 +0000
+++ src/window.c	2011-04-25 19:40:22 +0000
@@ -5794,8 +5794,7 @@
 
 struct save_window_data
   {
-    EMACS_UINT size;
-    struct Lisp_Vector *next_from_Lisp_Vector_struct;
+    struct vectorlike_header header;
     Lisp_Object selected_frame;
     Lisp_Object current_window;
     Lisp_Object current_buffer;
@@ -5817,10 +5816,7 @@
 /* This is saved as a Lisp_Vector  */
 struct saved_window
 {
-  /* these first two must agree with struct Lisp_Vector in lisp.h */
-  EMACS_UINT size;
-  struct Lisp_Vector *next_from_Lisp_Vector_struct;
-
+  struct vectorlike_header header;
   Lisp_Object window;
   Lisp_Object buffer, start, pointm, mark;
   Lisp_Object left_col, top_line, total_cols, total_lines;
@@ -6001,7 +5997,7 @@
 	 dead.  */
       delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
 
-      for (k = 0; k < saved_windows->size; k++)
+      for (k = 0; k < saved_windows->header.size; k++)
 	{
 	  p = SAVED_WINDOW_N (saved_windows, k);
 	  w = XWINDOW (p->window);
@@ -6884,10 +6880,10 @@
     return 0;
 
   /* Verify that the two confis have the same number of windows.  */
-  if (sw1->size != sw2->size)
+  if (sw1->header.size != sw2->header.size)
     return 0;
 
-  for (i = 0; i < sw1->size; i++)
+  for (i = 0; i < sw1->header.size; i++)
     {
       struct saved_window *p1, *p2;
       int w1_is_current, w2_is_current;

=== modified file 'src/window.h'
--- src/window.h	2011-04-14 06:48:41 +0000
+++ src/window.h	2011-04-25 19:40:22 +0000
@@ -88,10 +88,9 @@
 
 struct window
   {
-    /* The first two fields are really the header of a vector */
-    /* The window code does not refer to them.  */
-    EMACS_UINT size;
-    struct Lisp_Vector *vec_next;
+    /* This is for Lisp; the terminal code does not refer to it.  */
+    struct vectorlike_header header;
+
     /* The frame this window is on.  */
     Lisp_Object frame;
     /* t if this window is a minibuffer window.  */

=== modified file 'src/xdisp.c'
--- src/xdisp.c	2011-04-19 06:44:06 +0000
+++ src/xdisp.c	2011-04-25 21:34:39 +0000
@@ -3705,7 +3705,7 @@
     {
       struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp));
       it->dpvec = v->contents;
-      it->dpend = v->contents + v->size;
+      it->dpend = v->contents + v->header.size;
     }
   else
     {
@@ -5659,11 +5659,11 @@
 	      /* Return the first character from the display table
 		 entry, if not empty.  If empty, don't display the
 		 current character.  */
-	      if (v->size)
+	      if (v->header.size)
 		{
 		  it->dpvec_char_len = it->len;
 		  it->dpvec = v->contents;
-		  it->dpend = v->contents + v->size;
+		  it->dpend = v->contents + v->header.size;
 		  it->current.dpvec_index = 0;
 		  it->dpvec_face_id = -1;
 		  it->saved_face_id = it->face_id;
@@ -18136,7 +18136,7 @@
 
   /* Display all items of the menu bar.  */
   items = FRAME_MENU_BAR_ITEMS (it.f);
-  for (i = 0; i < XVECTOR (items)->size; i += 4)
+  for (i = 0; i < ASIZE (items); i += 4)
     {
       Lisp_Object string;
 
@@ -24828,7 +24828,7 @@
 	{
 	  struct Lisp_Vector *v = XVECTOR (XCDR (hot_spot));
 	  Lisp_Object *poly = v->contents;
-	  int n = v->size;
+	  int n = v->header.size;
 	  int i;
 	  int inside = 0;
 	  Lisp_Object lx, ly;

=== modified file 'src/xfaces.c'
--- src/xfaces.c	2011-04-16 21:28:14 +0000
+++ src/xfaces.c	2011-04-25 21:34:39 +0000
@@ -1848,7 +1848,7 @@
 
 #define LFACEP(LFACE)					\
      (VECTORP (LFACE)					\
-      && XVECTOR (LFACE)->size == LFACE_VECTOR_SIZE	\
+      && ASIZE (LFACE) == LFACE_VECTOR_SIZE		\
       && EQ (AREF (LFACE, 0), Qface))
 #endif
 

=== modified file 'src/xmenu.c'
--- src/xmenu.c	2011-04-16 15:38:15 +0000
+++ src/xmenu.c	2011-04-25 21:34:39 +0000
@@ -1011,7 +1011,7 @@
 
       menu_items = f->menu_bar_vector;
       menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
-      subitems = XVECTOR (items)->size / 4;
+      subitems = ASIZE (items) / 4;
       submenu_start = (int *) alloca (subitems * sizeof (int *));
       submenu_end = (int *) alloca (subitems * sizeof (int *));
       submenu_n_panes = (int *) alloca (subitems * sizeof (int));
@@ -1097,7 +1097,7 @@
       /* Now GC cannot happen during the lifetime of the widget_value,
 	 so it's safe to store data from a Lisp_String.  */
       wv = first_wv->contents;
-      for (i = 0; i < XVECTOR (items)->size; i += 4)
+      for (i = 0; i < ASIZE (items); i += 4)
 	{
 	  Lisp_Object string;
 	  string = XVECTOR (items)->contents[i + 1];
@@ -1123,7 +1123,7 @@
       first_wv = wv;
 
       items = FRAME_MENU_BAR_ITEMS (f);
-      for (i = 0; i < XVECTOR (items)->size; i += 4)
+      for (i = 0; i < ASIZE (items); i += 4)
 	{
 	  Lisp_Object string;
 

=== modified file 'src/xselect.c'
--- src/xselect.c	2011-04-19 06:52:00 +0000
+++ src/xselect.c	2011-04-25 21:34:39 +0000
@@ -423,7 +423,7 @@
       int size;
       int i;
       pairs = XCDR (target_type);
-      size = XVECTOR (pairs)->size;
+      size = ASIZE (pairs);
       /* If the target is MULTIPLE, then target_type looks like
 	  (MULTIPLE . [[SELECTION1 TARGET1] [SELECTION2 TARGET2] ... ])
 	 We modify the second element of each pair in the vector and
@@ -1261,12 +1261,12 @@
     return Fcons (XCAR (obj), copy_multiple_data (XCDR (obj)));
 
   CHECK_VECTOR (obj);
-  vec = Fmake_vector (size = XVECTOR (obj)->size, Qnil);
+  vec = Fmake_vector (size = ASIZE (obj), Qnil);
   for (i = 0; i < size; i++)
     {
       Lisp_Object vec2 = XVECTOR (obj)->contents [i];
       CHECK_VECTOR (vec2);
-      if (XVECTOR (vec2)->size != 2)
+      if (ASIZE (vec2) != 2)
 	/* ??? Confusing error message */
 	signal_error ("Vectors must be of length 2", vec2);
       XVECTOR (vec)->contents [i] = Fmake_vector (2, Qnil);
@@ -1878,7 +1878,7 @@
 	/* This vector is an ATOM set */
 	{
 	  if (NILP (type)) type = QATOM;
-	  *size_ret = XVECTOR (obj)->size;
+	  *size_ret = ASIZE (obj);
 	  *format_ret = 32;
 	  *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom));
 	  for (i = 0; i < *size_ret; i++)
@@ -1893,7 +1893,7 @@
 	/* This vector is an ATOM_PAIR set */
 	{
 	  if (NILP (type)) type = QATOM_PAIR;
-	  *size_ret = XVECTOR (obj)->size;
+	  *size_ret = ASIZE (obj);
 	  *format_ret = 32;
 	  *data_ret = (unsigned char *)
 	    xmalloc ((*size_ret) * sizeof (Atom) * 2);
@@ -1901,7 +1901,7 @@
 	    if (VECTORP (XVECTOR (obj)->contents [i]))
 	      {
 		Lisp_Object pair = XVECTOR (obj)->contents [i];
-		if (XVECTOR (pair)->size != 2)
+		if (ASIZE (pair) != 2)
 		  signal_error (
 	"Elements of the vector must be vectors of exactly two elements",
 				pair);
@@ -1923,7 +1923,7 @@
 	/* This vector is an INTEGER set, or something like it */
 	{
           int data_size = 2;
-	  *size_ret = XVECTOR (obj)->size;
+	  *size_ret = ASIZE (obj);
 	  if (NILP (type)) type = QINTEGER;
 	  *format_ret = 16;
 	  for (i = 0; i < *size_ret; i++)
@@ -1976,7 +1976,7 @@
   if (VECTORP (obj))
     {
       int i;
-      int size = XVECTOR (obj)->size;
+      int size = ASIZE (obj);
       Lisp_Object copy;
       if (size == 1)
 	return clean_local_selection_data (XVECTOR (obj)->contents [0]);


^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0
  2011-04-25 23:12   ` Paul Eggert
@ 2011-04-26 12:46     ` Stefan Monnier
  2011-04-26 20:06       ` Paul Eggert
  0 siblings, 1 reply; 7+ messages in thread
From: Stefan Monnier @ 2011-04-26 12:46 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 8546

>> +  {
>> +    EMACS_UINT size;
>> +    union {
>> +      struct buffer *buffer;
>> +      struct Lisp_Vector *vector;
>> +    } next;
>> +  };
>>
>> Why do you need to handle buffers specially here?  That sounds wrong.

> Purely as a convenience.  The code always uses the 'next' pointer as a
> struct buffer * (in alloc.c, buffer.c, data.c), or as a struct
> Lisp_Vector * (in alloc.c, fns.c).  As an alternative, we could

Ah, that makes sense (and deserves a brief comment).  Makes me wonder,
tho: why do we need the struct vectorlike_header?

IIUC the core part of your fix is to make all accesses to `size' use the
same type (i.e. Lisp_Vector), right?  Or does the use of the struct
help somehow?

While I understand the problem you're trying to fix, I don't know the
details of the C standard in sufficient detail to know exactly where's
the boundary between safe and unsafe.  And your patch should have
a comment next to the core part of the fix explaining which part is
important and needs to be preserved.

> I thought that the union made the code clearer and I know you

Yes, that's fine.  It just seemed odd to single out buffers.

>> Why does Lisp_Subr need to be a special case (IIUC this applies to
>> XSETTYPED_PSEUDOVECTOR and TYPED_PSEUDOVECTORP as well).

> struct Lisp_Subr has a "size" field but no "next" field.

Ah, yes, that makes sense as well (and deserves another brief comment).


        Stefan





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0
  2011-04-26 12:46     ` Stefan Monnier
@ 2011-04-26 20:06       ` Paul Eggert
  0 siblings, 0 replies; 7+ messages in thread
From: Paul Eggert @ 2011-04-26 20:06 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 8546-done, 8525-done

On 04/26/11 05:46, Stefan Monnier wrote:
 
> Ah, yes, that makes sense as well (and deserves another brief comment).

OK, thanks, I added comments for that, and for the other areas where
you requested comments, and merged it into the trunk.  I'll mark this
bug as done.  This merge also fixes bug 8525, which I'll also mark.

As mentioned in bug 8525, this fix assumes strtoumax and therefore
may require the Windows build to supply a 2-line inttypes.h if
Windows doesn't already have inttypes.h.  For details please see
<http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8525#14>.





^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2011-04-26 20:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-04-25  7:41 bug#8546: fix for Emacs pseudovector incompatibility with GCC 4.6.0 Paul Eggert
2011-04-25 10:23 ` Eli Zaretskii
2011-04-25 19:30   ` Paul Eggert
2011-04-25 14:05 ` Stefan Monnier
2011-04-25 23:12   ` Paul Eggert
2011-04-26 12:46     ` Stefan Monnier
2011-04-26 20:06       ` Paul Eggert

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).