Subject: Reorder lisp.h to declare types before using them

From: Paul Eggert <[email-masked]>
Date: Tue, 6 Dec 2016 23:19:19 -0800

Tags: patch

Attached is a patch to reorder src/lisp.h so that more types are declared before 
use. The main motivation is to eventually add support for 
-fcheck-pointer-bounds; future changes will need access to type sizes (e.g., 
XCONS might need sizeof (struct Lisp_Cons)), which should be easy after this 
change. Also, the change shortens lisp.h a bit and (if you ask me) makes it 
easier to read, since the basic functions for a type are now declared next to 
the type.

I would like to install this soon, and am posting this as a bug report to give 
Eli and others a heads-up, in case some MS-Windows module now needs to include 
process.h. This may be needed because XPROCESS is now defined in process.h 
instead of lisp.h; similarly for buffer.h, window.h, termhooks.h.
From d9627a9df1ef0e27df0e7eefa40aad85eeeb056c Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Tue, 6 Dec 2016 22:12:43 -0800
Subject: [PATCH] Reorder lisp.h to declare types before using them

Reorder lisp.h to put basic functions for types to be after the
corresponding type definitions.  This is a more-common programming
style in C, and will make it easier to port Emacs to gcc
-fcheck-pointer-bounds, since the functions now have access to the
corresponding types' sizes.  This patch does not change the code; it
just moves declarations and definitions and removes no-longer-needed
forward declarations.
* src/buffer.c, src/data.c, src/image.c:
Include process.h, for PROCESSP.
* src/buffer.h (BUFFERP, CHECK_BUFFER, XBUFFER):
* src/process.h (PROCESSP, CHECK_PROCESS, XPROCESS):
* src/terminal.h (TERMINALP, XTERMINAL):
* src/window.h (WINDOWP, CHECK_WINDOW, XWINDOW):
Move here from lisp.h.
* src/intervals.h: Include buffer.h, for BUFFERP.
* src/lisp.h: Reorder declarations and definitions as described above.
Move some symbols to other headers (noted above).
Remove forward decls that are no longer needed.
---
 src/buffer.c    |   1 +
 src/buffer.h    |  19 ++
 src/data.c      |   1 +
 src/image.c     |   1 +
 src/intervals.h |   3 +
 src/lisp.h      | 832 +++++++++++++++++++++++++-------------------------------
 src/process.h   |  19 ++
 src/termhooks.h |  13 +
 src/window.h    |  19 ++
 9 files changed, 448 insertions(+), 460 deletions(-)

diff --git a/src/buffer.c b/src/buffer.c
index 6815aa7..0ae0221 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -32,6 +32,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "lisp.h"
 #include "intervals.h"
+#include "process.h"
 #include "systime.h"
 #include "window.h"
 #include "commands.h"
diff --git a/src/buffer.h b/src/buffer.h
index 6ac161c..a8ca6a3 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -881,6 +881,25 @@ struct buffer
   Lisp_Object undo_list_;
 };
 
+INLINE bool
+BUFFERP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_BUFFER);
+}
+
+INLINE void
+CHECK_BUFFER (Lisp_Object x)
+{
+  CHECK_TYPE (BUFFERP (x), Qbufferp, x);
+}
+
+INLINE struct buffer *
+XBUFFER (Lisp_Object a)
+{
+  eassert (BUFFERP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 /* Most code should use these functions to set Lisp fields in struct
    buffer.  (Some setters that are private to a single .c file are
    defined as static in those files.)  */
diff --git a/src/data.c b/src/data.c
index 64cd8b2..405234e 100644
--- a/src/data.c
+++ b/src/data.c
@@ -31,6 +31,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "character.h"
 #include "buffer.h"
 #include "keyboard.h"
+#include "process.h"
 #include "frame.h"
 #include "keymap.h"
 
diff --git a/src/image.c b/src/image.c
index 89572b8..45010e7 100644
--- a/src/image.c
+++ b/src/image.c
@@ -36,6 +36,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "lisp.h"
 #include "frame.h"
+#include "process.h"
 #include "window.h"
 #include "buffer.h"
 #include "dispextern.h"
diff --git a/src/intervals.h b/src/intervals.h
index 9a38d84..b56c050 100644
--- a/src/intervals.h
+++ b/src/intervals.h
@@ -19,6 +19,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifndef EMACS_INTERVALS_H
 #define EMACS_INTERVALS_H
 
+#include "buffer.h"
+#include "lisp.h"
+
 INLINE_HEADER_BEGIN
 
 /* Basic data type for use of intervals.  */
diff --git a/src/lisp.h b/src/lisp.h
index b9c6289..c3eaf42 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -258,6 +258,11 @@ DEFINE_GDB_SYMBOL_BEGIN (bool, USE_LSB_TAG)
 #define USE_LSB_TAG (VAL_MAX / 2 < INTPTR_MAX)
 DEFINE_GDB_SYMBOL_END (USE_LSB_TAG)
 
+/* Mask for the value (as opposed to the type bits) of a Lisp object.  */
+DEFINE_GDB_SYMBOL_BEGIN (EMACS_INT, VALMASK)
+# define VALMASK (USE_LSB_TAG ? - (1 << GCTYPEBITS) : VAL_MAX)
+DEFINE_GDB_SYMBOL_END (VALMASK)
+
 #if !USE_LSB_TAG && !defined WIDE_EMACS_INT
 # error "USE_LSB_TAG not supported on this platform; please report this." \
 	"Try 'configure --with-wide-int' to work around the problem."
@@ -556,42 +561,9 @@ enum CHECK_LISP_OBJECT_TYPE { CHECK_LISP_OBJECT_TYPE = false };
 /* Forward declarations.  */
 
 /* Defined in this file.  */
-union Lisp_Fwd;
-INLINE bool BOOL_VECTOR_P (Lisp_Object);
-INLINE bool BUFFER_OBJFWDP (union Lisp_Fwd *);
-INLINE bool BUFFERP (Lisp_Object);
-INLINE bool CHAR_TABLE_P (Lisp_Object);
-INLINE Lisp_Object CHAR_TABLE_REF_ASCII (Lisp_Object, ptrdiff_t);
-INLINE bool (CONSP) (Lisp_Object);
-INLINE bool (FLOATP) (Lisp_Object);
-INLINE bool (INTEGERP) (Lisp_Object);
-INLINE bool (MARKERP) (Lisp_Object);
-INLINE bool (MISCP) (Lisp_Object);
-INLINE bool (NILP) (Lisp_Object);
-INLINE bool OVERLAYP (Lisp_Object);
-INLINE bool PROCESSP (Lisp_Object);
-INLINE bool PSEUDOVECTORP (Lisp_Object, int);
-INLINE bool SAVE_VALUEP (Lisp_Object);
-INLINE bool FINALIZERP (Lisp_Object);
-
-#ifdef HAVE_MODULES
-INLINE bool USER_PTRP (Lisp_Object);
-INLINE struct Lisp_User_Ptr *(XUSER_PTR) (Lisp_Object);
-#endif
 
 INLINE void set_sub_char_table_contents (Lisp_Object, ptrdiff_t,
 					      Lisp_Object);
-INLINE bool STRINGP (Lisp_Object);
-INLINE bool SUB_CHAR_TABLE_P (Lisp_Object);
-INLINE bool SUBRP (Lisp_Object);
-INLINE bool (SYMBOLP) (Lisp_Object);
-INLINE bool (VECTORLIKEP) (Lisp_Object);
-INLINE bool WINDOWP (Lisp_Object);
-INLINE bool TERMINALP (Lisp_Object);
-INLINE struct Lisp_Save_Value *XSAVE_VALUE (Lisp_Object);
-INLINE struct Lisp_Finalizer *XFINALIZER (Lisp_Object);
-INLINE struct Lisp_Symbol *(XSYMBOL) (Lisp_Object);
-INLINE void *(XUNTAG) (Lisp_Object, int);
 
 /* Defined in chartab.c.  */
 extern Lisp_Object char_table_ref (Lisp_Object, int);
@@ -600,8 +572,6 @@ extern void char_table_set (Lisp_Object, int, Lisp_Object);
 /* Defined in data.c.  */
 extern _Noreturn void wrong_type_argument (Lisp_Object, Lisp_Object);
 extern _Noreturn void wrong_choice (Lisp_Object, Lisp_Object);
-extern void notify_variable_watchers (Lisp_Object symbol, Lisp_Object newval,
-                                      Lisp_Object operation, Lisp_Object where);

 #ifdef CANNOT_DUMP
@@ -618,6 +588,56 @@ extern bool initialized;
 extern double extract_float (Lisp_Object);
 
 
+/* Low-level conversion and type checking.  */
+
+/* Convert a Lisp_Object to the corresponding EMACS_INT and vice versa.
+   At the machine level, these operations are no-ops.  */
+
+INLINE EMACS_INT
+(XLI) (Lisp_Object o)
+{
+  return lisp_h_XLI (o);
+}
+
+INLINE Lisp_Object
+(XIL) (EMACS_INT i)
+{
+  return lisp_h_XIL (i);
+}
+
+/* Extract A's type.  */
+
+INLINE enum Lisp_Type
+(XTYPE) (Lisp_Object a)
+{
+#if USE_LSB_TAG
+  return lisp_h_XTYPE (a);
+#else
+  EMACS_UINT i = XLI (a);
+  return USE_LSB_TAG ? i & ~VALMASK : i >> VALBITS;
+#endif
+}
+
+INLINE void
+(CHECK_TYPE) (int ok, Lisp_Object predicate, Lisp_Object x)
+{
+  lisp_h_CHECK_TYPE (ok, predicate, x);
+}
+
+/* Extract A's pointer value, assuming A's type is TYPE.  */
+
+INLINE void *
+(XUNTAG) (Lisp_Object a, int type)
+{
+#if USE_LSB_TAG
+  return lisp_h_XUNTAG (a, type);
+#else
+  intptr_t i = USE_LSB_TAG ? XLI (a) - type : XLI (a) & VALMASK;
+  return (void *) i;
+#endif
+}
+
+
 /* Interned state of a symbol.  */
 
 enum symbol_interned
@@ -746,6 +766,10 @@ struct Lisp_Symbol
   DEFINE_GDB_SYMBOL_BEGIN (Lisp_Object, name) \
   DEFINE_GDB_SYMBOL_END (LISPSYM_INITIALLY (name))
 
+/* The index of the C-defined Lisp symbol SYM.
+   This can be used in a static initializer.  */
+#define SYMBOL_INDEX(sym) i##sym
+
 /* By default, define macros for Qt, etc., as this leads to a bit
    better performance in the core Emacs interpreter.  A plugin can
    define DEFINE_NON_NIL_Q_SYMBOL_MACROS to be false, to be portable to
@@ -756,19 +780,43 @@ struct Lisp_Symbol
 
 #include "globals.h"
 
-/* Convert a Lisp_Object to the corresponding EMACS_INT and vice versa.
-   At the machine level, these operations are no-ops.  */
+INLINE bool
+(SYMBOLP) (Lisp_Object x)
+{
+  return lisp_h_SYMBOLP (x);
+}
 
-INLINE EMACS_INT
-(XLI) (Lisp_Object o)
+INLINE struct Lisp_Symbol *
+(XSYMBOL) (Lisp_Object a)
 {
-  return lisp_h_XLI (o);
+#if USE_LSB_TAG
+  return lisp_h_XSYMBOL (a);
+#else
+  eassert (SYMBOLP (a));
+  intptr_t i = (intptr_t) XUNTAG (a, Lisp_Symbol);
+  void *p = (char *) lispsym + i;
+  return p;
+#endif
 }
 
 INLINE Lisp_Object
-(XIL) (EMACS_INT i)
+make_lisp_symbol (struct Lisp_Symbol *sym)
 {
-  return lisp_h_XIL (i);
+  Lisp_Object a = XIL (TAG_SYMOFFSET ((char *) sym - (char *) lispsym));
+  eassert (XSYMBOL (a) == sym);
+  return a;
+}
+
+INLINE Lisp_Object
+builtin_lisp_symbol (int index)
+{
+  return make_lisp_symbol (lispsym + index);
+}
+
+INLINE void
+(CHECK_SYMBOL) (Lisp_Object x)
+{
+ lisp_h_CHECK_SYMBOL (x);
 }
 
 /* In the size word of a vector, this bit means the vector has been marked.  */
@@ -836,11 +884,6 @@ enum More_Lisp_Bits
    XCONS (tem) is the struct Lisp_Cons * pointing to the memory for
    that cons.  */
 
-/* Mask for the value (as opposed to the type bits) of a Lisp object.  */
-DEFINE_GDB_SYMBOL_BEGIN (EMACS_INT, VALMASK)
-# define VALMASK (USE_LSB_TAG ? - (1 << GCTYPEBITS) : VAL_MAX)
-DEFINE_GDB_SYMBOL_END (VALMASK)
-
 /* Largest and smallest representable fixnum values.  These are the C
    values.  They are macros for use in static initializers.  */
 #define MOST_POSITIVE_FIXNUM (EMACS_INT_MAX >> INTTYPEBITS)
@@ -868,24 +911,6 @@ INLINE EMACS_INT
   return n;
 }
 
-INLINE struct Lisp_Symbol *
-(XSYMBOL) (Lisp_Object a)
-{
-  return lisp_h_XSYMBOL (a);
-}
-
-INLINE enum Lisp_Type
-(XTYPE) (Lisp_Object a)
-{
-  return lisp_h_XTYPE (a);
-}
-
-INLINE void *
-(XUNTAG) (Lisp_Object a, int type)
-{
-  return lisp_h_XUNTAG (a, type);
-}
-
 #else /* ! USE_LSB_TAG */
 
 /* Although compiled only if ! USE_LSB_TAG, the following functions
@@ -937,24 +962,6 @@ XFASTINT (Lisp_Object a)
   return n;
 }
 
-/* Extract A's type.  */
-INLINE enum Lisp_Type
-XTYPE (Lisp_Object a)
-{
-  EMACS_UINT i = XLI (a);
-  return USE_LSB_TAG ? i & ~VALMASK : i >> VALBITS;
-}
-
-/* Extract A's value as a symbol.  */
-INLINE struct Lisp_Symbol *
-XSYMBOL (Lisp_Object a)
-{
-  eassert (SYMBOLP (a));
-  intptr_t i = (intptr_t) XUNTAG (a, Lisp_Symbol);
-  void *p = (char *) lispsym + i;
-  return p;
-}
-
 /* Extract A's pointer value, assuming A's type is TYPE.  */
 INLINE void *
 XUNTAG (Lisp_Object a, int type)
@@ -1014,97 +1021,6 @@ clip_to_bounds (ptrdiff_t lower, EMACS_INT num, ptrdiff_t upper)
 }
 
 
-/* Extract a value or address from a Lisp_Object.  */
-
-INLINE struct Lisp_Cons *
-(XCONS) (Lisp_Object a)
-{
-  return lisp_h_XCONS (a);
-}
-
-INLINE struct Lisp_Vector *
-XVECTOR (Lisp_Object a)
-{
-  eassert (VECTORLIKEP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_String *
-XSTRING (Lisp_Object a)
-{
-  eassert (STRINGP (a));
-  return XUNTAG (a, Lisp_String);
-}
-
-/* The index of the C-defined Lisp symbol SYM.
-   This can be used in a static initializer.  */
-#define SYMBOL_INDEX(sym) i##sym
-
-INLINE struct Lisp_Float *
-XFLOAT (Lisp_Object a)
-{
-  eassert (FLOATP (a));
-  return XUNTAG (a, Lisp_Float);
-}
-
-/* Pseudovector types.  */
-
-INLINE struct Lisp_Process *
-XPROCESS (Lisp_Object a)
-{
-  eassert (PROCESSP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct window *
-XWINDOW (Lisp_Object a)
-{
-  eassert (WINDOWP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct terminal *
-XTERMINAL (Lisp_Object a)
-{
-  eassert (TERMINALP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_Subr *
-XSUBR (Lisp_Object a)
-{
-  eassert (SUBRP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct buffer *
-XBUFFER (Lisp_Object a)
-{
-  eassert (BUFFERP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_Char_Table *
-XCHAR_TABLE (Lisp_Object a)
-{
-  eassert (CHAR_TABLE_P (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_Sub_Char_Table *
-XSUB_CHAR_TABLE (Lisp_Object a)
-{
-  eassert (SUB_CHAR_TABLE_P (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_Bool_Vector *
-XBOOL_VECTOR (Lisp_Object a)
-{
-  eassert (BOOL_VECTOR_P (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
 /* Construct a Lisp_Object from a value or address.  */
 
 INLINE Lisp_Object
@@ -1115,18 +1031,10 @@ make_lisp_ptr (void *ptr, enum Lisp_Type type)
   return a;
 }
 
-INLINE Lisp_Object
-make_lisp_symbol (struct Lisp_Symbol *sym)
-{
-  Lisp_Object a = XIL (TAG_SYMOFFSET ((char *) sym - (char *) lispsym));
-  eassert (XSYMBOL (a) == sym);
-  return a;
-}
-
-INLINE Lisp_Object
-builtin_lisp_symbol (int index)
+INLINE bool
+(INTEGERP) (Lisp_Object x)
 {
-  return make_lisp_symbol (lispsym + index);
+  return lisp_h_INTEGERP (x);
 }
 
 #define XSETINT(a, b) ((a) = make_number (b))
@@ -1191,14 +1099,6 @@ make_pointer_integer (void *p)
   return a;
 }
 
-/* Type checking.  */
-
-INLINE void
-(CHECK_TYPE) (int ok, Lisp_Object predicate, Lisp_Object x)
-{
-  lisp_h_CHECK_TYPE (ok, predicate, x);
-}
-
 /* See the macros in intervals.h.  */
 
 typedef struct interval *INTERVAL;
@@ -1218,22 +1118,46 @@ struct GCALIGNED Lisp_Cons
     } u;
   };
 
-/* Take the car or cdr of something known to be a cons cell.  */
-/* The _addr functions shouldn't be used outside of the minimal set
-   of code that has to know what a cons cell looks like.  Other code not
-   part of the basic lisp implementation should assume that the car and cdr
-   fields are not accessible.  (What if we want to switch to
-   a copying collector someday?  Cached cons cell field addresses may be
-   invalidated at arbitrary points.)  */
-INLINE Lisp_Object *
-xcar_addr (Lisp_Object c)
+INLINE bool
+(NILP) (Lisp_Object x)
 {
-  return &XCONS (c)->car;
+  return lisp_h_NILP (x);
 }
-INLINE Lisp_Object *
-xcdr_addr (Lisp_Object c)
+
+INLINE bool
+(CONSP) (Lisp_Object x)
 {
-  return &XCONS (c)->u.cdr;
+  return lisp_h_CONSP (x);
+}
+
+INLINE void
+CHECK_CONS (Lisp_Object x)
+{
+  CHECK_TYPE (CONSP (x), Qconsp, x);
+}
+
+INLINE struct Lisp_Cons *
+(XCONS) (Lisp_Object a)
+{
+  return lisp_h_XCONS (a);
+}
+
+/* Take the car or cdr of something known to be a cons cell.  */
+/* The _addr functions shouldn't be used outside of the minimal set
+   of code that has to know what a cons cell looks like.  Other code not
+   part of the basic lisp implementation should assume that the car and cdr
+   fields are not accessible.  (What if we want to switch to
+   a copying collector someday?  Cached cons cell field addresses may be
+   invalidated at arbitrary points.)  */
+INLINE Lisp_Object *
+xcar_addr (Lisp_Object c)
+{
+  return &XCONS (c)->car;
+}
+INLINE Lisp_Object *
+xcdr_addr (Lisp_Object c)
+{
+  return &XCONS (c)->u.cdr;
 }
 
 /* Use these from normal code.  */
@@ -1307,6 +1231,25 @@ struct GCALIGNED Lisp_String
     unsigned char *data;
   };
 
+INLINE bool
+STRINGP (Lisp_Object x)
+{
+  return XTYPE (x) == Lisp_String;
+}
+
+INLINE void
+CHECK_STRING (Lisp_Object x)
+{
+  CHECK_TYPE (STRINGP (x), Qstringp, x);
+}
+
+INLINE struct Lisp_String *
+XSTRING (Lisp_Object a)
+{
+  eassert (STRINGP (a));
+  return XUNTAG (a, Lisp_String);
+}
+
 /* True if STR is a multibyte string.  */
 INLINE bool
 STRING_MULTIBYTE (Lisp_Object str)
@@ -1441,6 +1384,62 @@ struct Lisp_Vector
     Lisp_Object contents[FLEXIBLE_ARRAY_MEMBER];
   };
 
+INLINE bool
+(VECTORLIKEP) (Lisp_Object x)
+{
+  return lisp_h_VECTORLIKEP (x);
+}
+
+INLINE struct Lisp_Vector *
+XVECTOR (Lisp_Object a)
+{
+  eassert (VECTORLIKEP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
+INLINE ptrdiff_t
+ASIZE (Lisp_Object array)
+{
+  ptrdiff_t size = XVECTOR (array)->header.size;
+  eassume (0 <= size);
+  return size;
+}
+
+INLINE bool
+VECTORP (Lisp_Object x)
+{
+  return VECTORLIKEP (x) && ! (ASIZE (x) & PSEUDOVECTOR_FLAG);
+}
+
+INLINE void
+CHECK_VECTOR (Lisp_Object x)
+{
+  CHECK_TYPE (VECTORP (x), Qvectorp, x);
+}
+
+/* A pseudovector is like a vector, but has other non-Lisp components.  */
+
+INLINE bool
+PSEUDOVECTOR_TYPEP (struct vectorlike_header *a, int code)
+{
+  return ((a->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))
+	  == (PSEUDOVECTOR_FLAG | (code << PSEUDOVECTOR_AREA_BITS)));
+}
+
+/* True if A is a pseudovector whose code is CODE.  */
+INLINE bool
+PSEUDOVECTORP (Lisp_Object a, int code)
+{
+  if (! VECTORLIKEP (a))
+    return false;
+  else
+    {
+      /* Converting to struct vectorlike_header * avoids aliasing issues.  */
+      struct vectorlike_header *h = XUNTAG (a, Lisp_Vectorlike);
+      return PSEUDOVECTOR_TYPEP (h, code);
+    }
+}
+
 /* A boolvector is a kind of vectorlike, with contents like a string.  */
 
 struct Lisp_Bool_Vector
@@ -1457,6 +1456,51 @@ struct Lisp_Bool_Vector
     bits_word data[FLEXIBLE_ARRAY_MEMBER];
   };
 
+/* Some handy constants for calculating sizes
+   and offsets, mostly of vectorlike objects.   */
+
+enum
+  {
+    header_size = offsetof (struct Lisp_Vector, contents),
+    bool_header_size = offsetof (struct Lisp_Bool_Vector, data),
+    word_size = sizeof (Lisp_Object)
+  };
+
+/* The number of data words and bytes in a bool vector with SIZE bits.  */
+
+INLINE EMACS_INT
+bool_vector_words (EMACS_INT size)
+{
+  eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
+  return (size + BITS_PER_BITS_WORD - 1) / BITS_PER_BITS_WORD;
+}
+
+INLINE EMACS_INT
+bool_vector_bytes (EMACS_INT size)
+{
+  eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
+  return (size + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR;
+}
+
+INLINE bool
+BOOL_VECTOR_P (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_BOOL_VECTOR);
+}
+
+INLINE void
+CHECK_BOOL_VECTOR (Lisp_Object x)
+{
+  CHECK_TYPE (BOOL_VECTOR_P (x), Qbool_vector_p, x);
+}
+
+INLINE struct Lisp_Bool_Vector *
+XBOOL_VECTOR (Lisp_Object a)
+{
+  eassert (BOOL_VECTOR_P (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 INLINE EMACS_INT
 bool_vector_size (Lisp_Object a)
 {
@@ -1477,22 +1521,6 @@ bool_vector_uchar_data (Lisp_Object a)
   return (unsigned char *) bool_vector_data (a);
 }
 
-/* The number of data words and bytes in a bool vector with SIZE bits.  */
-
-INLINE EMACS_INT
-bool_vector_words (EMACS_INT size)
-{
-  eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
-  return (size + BITS_PER_BITS_WORD - 1) / BITS_PER_BITS_WORD;
-}
-
-INLINE EMACS_INT
-bool_vector_bytes (EMACS_INT size)
-{
-  eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
-  return (size + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR;
-}
-
 /* True if A's Ith bit is set.  */
 
 INLINE bool
@@ -1525,16 +1553,6 @@ bool_vector_set (Lisp_Object a, EMACS_INT i, bool b)
     *addr &= ~ (1 << (i % BOOL_VECTOR_BITS_PER_CHAR));
 }
 
-/* Some handy constants for calculating sizes
-   and offsets, mostly of vectorlike objects.   */
-
-enum
-  {
-    header_size = offsetof (struct Lisp_Vector, contents),
-    bool_header_size = offsetof (struct Lisp_Bool_Vector, data),
-    word_size = sizeof (Lisp_Object)
-  };
-
 /* Conveniences for dealing with Lisp arrays.  */
 
 INLINE Lisp_Object
@@ -1550,14 +1568,6 @@ aref_addr (Lisp_Object array, ptrdiff_t idx)
 }
 
 INLINE ptrdiff_t
-ASIZE (Lisp_Object array)
-{
-  ptrdiff_t size = XVECTOR (array)->header.size;
-  eassume (0 <= size);
-  return size;
-}
-
-INLINE ptrdiff_t
 gc_asize (Lisp_Object array)
 {
   /* Like ASIZE, but also can be used in the garbage collector.  */
@@ -1674,6 +1684,19 @@ struct Lisp_Char_Table
     Lisp_Object extras[FLEXIBLE_ARRAY_MEMBER];
   };
 
+INLINE bool
+CHAR_TABLE_P (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_CHAR_TABLE);
+}
+
+INLINE struct Lisp_Char_Table *
+XCHAR_TABLE (Lisp_Object a)
+{
+  eassert (CHAR_TABLE_P (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 struct Lisp_Sub_Char_Table
   {
     /* HEADER.SIZE is the vector's size field, which also holds the
@@ -1695,6 +1718,19 @@ struct Lisp_Sub_Char_Table
     Lisp_Object contents[FLEXIBLE_ARRAY_MEMBER];
   };
 
+INLINE bool
+SUB_CHAR_TABLE_P (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_SUB_CHAR_TABLE);
+}
+
+INLINE struct Lisp_Sub_Char_Table *
+XSUB_CHAR_TABLE (Lisp_Object a)
+{
+  eassert (SUB_CHAR_TABLE_P (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 INLINE Lisp_Object
 CHAR_TABLE_REF_ASCII (Lisp_Object ct, ptrdiff_t idx)
 {
@@ -1760,6 +1796,19 @@ struct Lisp_Subr
     EMACS_INT doc;
   };
 
+INLINE bool
+SUBRP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_SUBR);
+}
+
+INLINE struct Lisp_Subr *
+XSUBR (Lisp_Object a)
+{
+  eassert (SUBRP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 enum char_table_specials
   {
     /* This is the number of slots that every char table must have.  This
@@ -2070,6 +2119,25 @@ struct Lisp_Misc_Any		/* Supertype of all Misc types.  */
   unsigned spacer : 15;
 };
 
+INLINE bool
+(MISCP) (Lisp_Object x)
+{
+  return lisp_h_MISCP (x);
+}
+
+INLINE struct Lisp_Misc_Any *
+XMISCANY (Lisp_Object a)
+{
+  eassert (MISCP (a));
+  return XUNTAG (a, Lisp_Misc);
+}
+
+INLINE enum Lisp_Misc_Type
+XMISCTYPE (Lisp_Object a)
+{
+  return XMISCANY (a)->type;
+}
+
 struct Lisp_Marker
 {
   ENUM_BF (Lisp_Misc_Type) type : 16;		/* = Lisp_Misc_Marker */
@@ -2227,6 +2295,19 @@ struct Lisp_Save_Value
     } data[SAVE_VALUE_SLOTS];
   };
 
+INLINE bool
+SAVE_VALUEP (Lisp_Object x)
+{
+  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Save_Value;
+}
+
+INLINE struct Lisp_Save_Value *
+XSAVE_VALUE (Lisp_Object a)
+{
+  eassert (SAVE_VALUEP (a));
+  return XUNTAG (a, Lisp_Misc);
+}
+
 /* Return the type of V's Nth saved value.  */
 INLINE int
 save_type (struct Lisp_Save_Value *v, int n)
@@ -2307,6 +2388,19 @@ struct Lisp_Finalizer
     Lisp_Object function;
   };
 
+INLINE bool
+FINALIZERP (Lisp_Object x)
+{
+  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Finalizer;
+}
+
+INLINE struct Lisp_Finalizer *
+XFINALIZER (Lisp_Object a)
+{
+  eassert (FINALIZERP (a));
+  return XUNTAG (a, Lisp_Misc);
+}
+
 /* A miscellaneous object, when it's on the free list.  */
 struct Lisp_Free
   {
@@ -2338,53 +2432,44 @@ XMISC (Lisp_Object a)
   return XUNTAG (a, Lisp_Misc);
 }
 
-INLINE struct Lisp_Misc_Any *
-XMISCANY (Lisp_Object a)
-{
-  eassert (MISCP (a));
-  return & XMISC (a)->u_any;
-}
-
-INLINE enum Lisp_Misc_Type
-XMISCTYPE (Lisp_Object a)
+INLINE bool
+(MARKERP) (Lisp_Object x)
 {
-  return XMISCANY (a)->type;
+  return lisp_h_MARKERP (x);
 }
 
 INLINE struct Lisp_Marker *
 XMARKER (Lisp_Object a)
 {
   eassert (MARKERP (a));
-  return & XMISC (a)->u_marker;
+  return XUNTAG (a, Lisp_Misc);
 }
 
-INLINE struct Lisp_Overlay *
-XOVERLAY (Lisp_Object a)
+INLINE bool
+OVERLAYP (Lisp_Object x)
 {
-  eassert (OVERLAYP (a));
-  return & XMISC (a)->u_overlay;
+  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Overlay;
 }
 
-INLINE struct Lisp_Save_Value *
-XSAVE_VALUE (Lisp_Object a)
+INLINE struct Lisp_Overlay *
+XOVERLAY (Lisp_Object a)
 {
-  eassert (SAVE_VALUEP (a));
-  return & XMISC (a)->u_save_value;
+  eassert (OVERLAYP (a));
+  return XUNTAG (a, Lisp_Misc);
 }
 
-INLINE struct Lisp_Finalizer *
-XFINALIZER (Lisp_Object a)
+#ifdef HAVE_MODULES
+INLINE bool
+USER_PTRP (Lisp_Object x)
 {
-  eassert (FINALIZERP (a));
-  return & XMISC (a)->u_finalizer;
+  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_User_Ptr;
 }
 
-#ifdef HAVE_MODULES
 INLINE struct Lisp_User_Ptr *
 XUSER_PTR (Lisp_Object a)
 {
   eassert (USER_PTRP (a));
-  return & XMISC (a)->u_user_ptr;
+  return XUNTAG (a, Lisp_Misc);
 }
 #endif
 
@@ -2502,6 +2587,12 @@ XFWDTYPE (union Lisp_Fwd *a)
   return a->u_intfwd.type;
 }
 
+INLINE bool
+BUFFER_OBJFWDP (union Lisp_Fwd *a)
+{
+  return XFWDTYPE (a) == Lisp_Fwd_Buffer_Obj;
+}
+
 INLINE struct Lisp_Buffer_Objfwd *
 XBUFFER_OBJFWD (union Lisp_Fwd *a)
 {
@@ -2519,6 +2610,19 @@ struct Lisp_Float
     } u;
   };
 
+INLINE bool
+(FLOATP) (Lisp_Object x)
+{
+  return lisp_h_FLOATP (x);
+}
+
+INLINE struct Lisp_Float *
+XFLOAT (Lisp_Object a)
+{
+  eassert (FLOATP (a));
+  return XUNTAG (a, Lisp_Float);
+}
+
 INLINE double
 XFLOAT_DATA (Lisp_Object f)
 {
@@ -2582,12 +2686,6 @@ enum char_bits
 /* Data type checking.  */
 
 INLINE bool
-(NILP) (Lisp_Object x)
-{
-  return lisp_h_NILP (x);
-}
-
-INLINE bool
 NUMBERP (Lisp_Object x)
 {
   return INTEGERP (x) || FLOATP (x);
@@ -2610,109 +2708,11 @@ RANGED_INTEGERP (intmax_t lo, Lisp_Object x, intmax_t hi)
    && XINT (x) <= TYPE_MAXIMUM (type))
 
 INLINE bool
-(CONSP) (Lisp_Object x)
-{
-  return lisp_h_CONSP (x);
-}
-INLINE bool
-(FLOATP) (Lisp_Object x)
-{
-  return lisp_h_FLOATP (x);
-}
-INLINE bool
-(MISCP) (Lisp_Object x)
-{
-  return lisp_h_MISCP (x);
-}
-INLINE bool
-(SYMBOLP) (Lisp_Object x)
-{
-  return lisp_h_SYMBOLP (x);
-}
-INLINE bool
-(INTEGERP) (Lisp_Object x)
-{
-  return lisp_h_INTEGERP (x);
-}
-INLINE bool
-(VECTORLIKEP) (Lisp_Object x)
-{
-  return lisp_h_VECTORLIKEP (x);
-}
-INLINE bool
-(MARKERP) (Lisp_Object x)
-{
-  return lisp_h_MARKERP (x);
-}
-
-INLINE bool
-STRINGP (Lisp_Object x)
-{
-  return XTYPE (x) == Lisp_String;
-}
-INLINE bool
-VECTORP (Lisp_Object x)
-{
-  return VECTORLIKEP (x) && ! (ASIZE (x) & PSEUDOVECTOR_FLAG);
-}
-INLINE bool
-OVERLAYP (Lisp_Object x)
-{
-  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Overlay;
-}
-INLINE bool
-SAVE_VALUEP (Lisp_Object x)
-{
-  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Save_Value;
-}
-
-INLINE bool
-FINALIZERP (Lisp_Object x)
-{
-  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Finalizer;
-}
-
-#ifdef HAVE_MODULES
-INLINE bool
-USER_PTRP (Lisp_Object x)
-{
-  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_User_Ptr;
-}
-#endif
-
-INLINE bool
 AUTOLOADP (Lisp_Object x)
 {
   return CONSP (x) && EQ (Qautoload, XCAR (x));
 }
 
-INLINE bool
-BUFFER_OBJFWDP (union Lisp_Fwd *a)
-{
-  return XFWDTYPE (a) == Lisp_Fwd_Buffer_Obj;
-}
-
-INLINE bool
-PSEUDOVECTOR_TYPEP (struct vectorlike_header *a, int code)
-{
-  return ((a->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))
-	  == (PSEUDOVECTOR_FLAG | (code << PSEUDOVECTOR_AREA_BITS)));
-}
-
-/* True if A is a pseudovector whose code is CODE.  */
-INLINE bool
-PSEUDOVECTORP (Lisp_Object a, int code)
-{
-  if (! VECTORLIKEP (a))
-    return false;
-  else
-    {
-      /* Converting to struct vectorlike_header * avoids aliasing issues.  */
-      struct vectorlike_header *h = XUNTAG (a, Lisp_Vectorlike);
-      return PSEUDOVECTOR_TYPEP (h, code);
-    }
-}
-
 
 /* Test for specific pseudovector types.  */
 
@@ -2723,60 +2723,12 @@ WINDOW_CONFIGURATIONP (Lisp_Object a)
 }
 
 INLINE bool
-PROCESSP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_PROCESS);
-}
-
-INLINE bool
-WINDOWP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_WINDOW);
-}
-
-INLINE bool
-TERMINALP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_TERMINAL);
-}
-
-INLINE bool
-SUBRP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_SUBR);
-}
-
-INLINE bool
 COMPILEDP (Lisp_Object a)
 {
   return PSEUDOVECTORP (a, PVEC_COMPILED);
 }
 
 INLINE bool
-BUFFERP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_BUFFER);
-}
-
-INLINE bool
-CHAR_TABLE_P (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_CHAR_TABLE);
-}
-
-INLINE bool
-SUB_CHAR_TABLE_P (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_SUB_CHAR_TABLE);
-}
-
-INLINE bool
-BOOL_VECTOR_P (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_BOOL_VECTOR);
-}
-
-INLINE bool
 FRAMEP (Lisp_Object a)
 {
   return PSEUDOVECTORP (a, PVEC_FRAME);
@@ -2809,42 +2761,16 @@ INLINE void
 }
 
 INLINE void
-(CHECK_SYMBOL) (Lisp_Object x)
-{
- lisp_h_CHECK_SYMBOL (x);
-}
-
-INLINE void
 (CHECK_NUMBER) (Lisp_Object x)
 {
   lisp_h_CHECK_NUMBER (x);
 }
 
 INLINE void
-CHECK_STRING (Lisp_Object x)
-{
-  CHECK_TYPE (STRINGP (x), Qstringp, x);
-}
-INLINE void
 CHECK_STRING_CAR (Lisp_Object x)
 {
   CHECK_TYPE (STRINGP (XCAR (x)), Qstringp, XCAR (x));
 }
-INLINE void
-CHECK_CONS (Lisp_Object x)
-{
-  CHECK_TYPE (CONSP (x), Qconsp, x);
-}
-INLINE void
-CHECK_VECTOR (Lisp_Object x)
-{
-  CHECK_TYPE (VECTORP (x), Qvectorp, x);
-}
-INLINE void
-CHECK_BOOL_VECTOR (Lisp_Object x)
-{
-  CHECK_TYPE (BOOL_VECTOR_P (x), Qbool_vector_p, x);
-}
 /* This is a bit special because we always need size afterwards.  */
 INLINE ptrdiff_t
 CHECK_VECTOR_OR_STRING (Lisp_Object x)
@@ -2861,23 +2787,6 @@ CHECK_ARRAY (Lisp_Object x, Lisp_Object predicate)
   CHECK_TYPE (ARRAYP (x), predicate, x);
 }
 INLINE void
-CHECK_BUFFER (Lisp_Object x)
-{
-  CHECK_TYPE (BUFFERP (x), Qbufferp, x);
-}
-INLINE void
-CHECK_WINDOW (Lisp_Object x)
-{
-  CHECK_TYPE (WINDOWP (x), Qwindowp, x);
-}
-#ifdef subprocesses
-INLINE void
-CHECK_PROCESS (Lisp_Object x)
-{
-  CHECK_TYPE (PROCESSP (x), Qprocessp, x);
-}
-#endif
-INLINE void
 CHECK_NATNUM (Lisp_Object x)
 {
   CHECK_TYPE (NATNUMP (x), Qwholenump, x);
@@ -3380,6 +3289,8 @@ set_sub_char_table_contents (Lisp_Object table, ptrdiff_t idx, Lisp_Object val)
 }
 
 /* Defined in data.c.  */
+extern void notify_variable_watchers (Lisp_Object, Lisp_Object,
+				      Lisp_Object, Lisp_Object);
 extern Lisp_Object indirect_function (Lisp_Object);
 extern Lisp_Object find_symbol_value (Lisp_Object);
 enum Arith_Comparison {
@@ -4194,6 +4105,7 @@ extern bool inhibit_window_system;
 extern bool running_asynch_code;
 
 /* Defined in process.c.  */
+struct Lisp_Process;
 extern void kill_buffer_processes (Lisp_Object);
 extern int wait_reading_process_output (intmax_t, int, int, bool, Lisp_Object,
 					struct Lisp_Process *, int);
diff --git a/src/process.h b/src/process.h
index 24c6282..8f28ddb 100644
--- a/src/process.h
+++ b/src/process.h
@@ -199,6 +199,25 @@ struct Lisp_Process
 #endif
 };
 
+INLINE bool
+PROCESSP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_PROCESS);
+}
+
+INLINE void
+CHECK_PROCESS (Lisp_Object x)
+{
+  CHECK_TYPE (PROCESSP (x), Qprocessp, x);
+}
+
+INLINE struct Lisp_Process *
+XPROCESS (Lisp_Object a)
+{
+  eassert (PROCESSP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 /* Every field in the preceding structure except for the first two
    must be a Lisp_Object, for GC's sake.  */
 
diff --git a/src/termhooks.h b/src/termhooks.h
index 03416cb..81e06d9 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -654,6 +654,19 @@ struct terminal
   void (*delete_terminal_hook) (struct terminal *);
 };
 
+INLINE bool
+TERMINALP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_TERMINAL);
+}
+
+INLINE struct terminal *
+XTERMINAL (Lisp_Object a)
+{
+  eassert (TERMINALP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 /* Most code should use these functions to set Lisp fields in struct
    terminal.  */
 INLINE void
diff --git a/src/window.h b/src/window.h
index 4a102f2..717f972 100644
--- a/src/window.h
+++ b/src/window.h
@@ -397,6 +397,25 @@ struct window
     ptrdiff_t window_end_bytepos;
   };
 
+INLINE bool
+WINDOWP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_WINDOW);
+}
+
+INLINE void
+CHECK_WINDOW (Lisp_Object x)
+{
+  CHECK_TYPE (WINDOWP (x), Qwindowp, x);
+}
+
+INLINE struct window *
+XWINDOW (Lisp_Object a)
+{
+  eassert (WINDOWP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 /* Most code should use these functions to set Lisp fields in struct
    window.  */
 INLINE void
-- 
2.9.3