changeset 1296:87084e8445a7

[xemacs-hg @ 2003-02-14 09:50:15 by ben] syntax-table fixes 1. the updating of mirror tables every time a syntax table was modified was taking up huge amounts of time so i added a dirty flag and made the updating "just-in-time". 2. no-longer-used char-table-entries were not getting "freed", generating tons of garbage. 3. syntax_match() was being incorrectly called on mirror tables in the cache, not the original syntax table. buffer.c, syntax.c: Move syntax table description from buffer.c to syntax.c. chartab.c, chartab.h: Free extra char table entries to avoid excessive garbage. Add flags for dirty and mirror_table_p to char tables. Add a back pointer from mirror tables to the original syntax table. When modifying a syntax table, don't update the mirror table right away, just mark as dirty. Add various asserts to make sure we are dealing with the right type of table (mirror or non-mirror). font-lock.c, syntax.c, syntax.h: Add entry to syntax caches for the non-mirror table. Set it appropriately when initializing the syntax table. Use it, not the mirror table, for calls to syntax_match(). Don't create a bogus float each time, just once at startup. Add some asserts, as in chartab.c. syntax.h: When retrieving the syntax code, check the dirty flag and update the mirror tables as appropriate. Add some asserts, as above.
author ben
date Fri, 14 Feb 2003 09:50:17 +0000
parents 064ef1d07d63
children 6c21360a544b
files src/ChangeLog src/buffer.c src/chartab.c src/chartab.h src/font-lock.c src/syntax.c src/syntax.h
diffstat 7 files changed, 271 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Fri Feb 14 07:54:29 2003 +0000
+++ b/src/ChangeLog	Fri Feb 14 09:50:17 2003 +0000
@@ -1,3 +1,54 @@
+2003-02-14  Ben Wing  <ben@xemacs.org>
+
+	* buffer.c:
+	* syntax.c:
+	Move syntax table description from buffer.c to syntax.c.
+	
+	* chartab.c:
+	* chartab.c (set_char_table_dirty):
+	* chartab.c (fill_char_table):
+	* chartab.c (Fmake_char_table):
+	* chartab.c (Fcopy_char_table):
+	* chartab.c (get_range_char_table_1):
+	* chartab.c (get_range_char_table):
+	* chartab.c (put_char_table):
+	* chartab.h:
+	* chartab.h (struct Lisp_Char_Table):
+	Free extra char table entries to avoid excessive garbage.
+	Add flags for dirty and mirror_table_p to char tables.
+	Add a back pointer from mirror tables to the original syntax table.
+	When modifying a syntax table, don't update the mirror table right
+	away, just mark as dirty.
+	Add various asserts to make sure we are dealing with the right type
+	of table (mirror or non-mirror).
+	
+	* font-lock.c:
+	* font-lock.c (find_context):
+	* syntax.c (init_syntax_cache):
+	* syntax.c (setup_syntax_cache):
+	* syntax.c (mark_buffer_syntax_cache):
+	* syntax.c (init_buffer_syntax_cache):
+	* syntax.c (syntax_cache_table_was_changed):
+	* syntax.c (update_syntax_cache):
+	* syntax.c (scan_lists):
+	* syntax.c (scan_sexps_forward):
+	* syntax.c (copy_if_not_already_present):
+	* syntax.c (update_just_this_syntax_table):
+	* syntax.c (update_syntax_table):
+	* syntax.c (vars_of_syntax):
+	* syntax.h:
+	* syntax.h (struct syntax_cache):
+	Add entry to syntax caches for the non-mirror table.  Set it
+	appropriately when initializing the syntax table.  Use it, not
+	the mirror table, for calls to syntax_match().
+	Don't create a bogus float each time, just once at startup.
+	Add some asserts, as in chartab.c.
+
+	* syntax.h (SYNTAX_CODE_FROM_CACHE):
+	When retrieving the syntax code, check the dirty flag and update
+	the mirror tables as appropriate.
+	Add some asserts, as above.
+	
 2003-02-14  Ben Wing  <ben@xemacs.org>
 
 	* scrollbar.c (specifier_vars_of_scrollbar):
--- a/src/buffer.c	Fri Feb 14 07:54:29 2003 +0000
+++ b/src/buffer.c	Fri Feb 14 09:50:17 2003 +0000
@@ -238,20 +238,6 @@
   buffer_text_description_1
 };
 
-static const struct memory_description syntax_cache_description_1 [] = {
-  { XD_LISP_OBJECT, offsetof (struct syntax_cache, object) },
-  { XD_LISP_OBJECT, offsetof (struct syntax_cache, buffer) },
-  { XD_LISP_OBJECT, offsetof (struct syntax_cache, current_syntax_table) },
-  { XD_LISP_OBJECT, offsetof (struct syntax_cache, start) },
-  { XD_LISP_OBJECT, offsetof (struct syntax_cache, end) },
-  { XD_END }
-};
-
-static const struct sized_memory_description syntax_cache_description = {
-  sizeof (struct syntax_cache),
-  syntax_cache_description_1
-};
-
 static const struct memory_description buffer_description [] = {
 #define MARKED_SLOT(x) { XD_LISP_OBJECT, offsetof (struct buffer, x) },
 #include "bufslots.h"
--- a/src/chartab.c	Fri Feb 14 07:54:29 2003 +0000
+++ b/src/chartab.c	Fri Feb 14 09:50:17 2003 +0000
@@ -1,7 +1,7 @@
 /* XEmacs routines to deal with char tables.
    Copyright (C) 1992, 1995 Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
-   Copyright (C) 1995, 1996, 2002 Ben Wing.
+   Copyright (C) 1995, 1996, 2002, 2003 Ben Wing.
    Copyright (C) 1995, 1997, 1999 Electrotechnical Laboratory, JAPAN.
    Licensed to the Free Software Foundation.
 
@@ -444,13 +444,20 @@
   return char_table_type_to_symbol (XCHAR_TABLE (char_table)->type);
 }
 
+static void
+set_char_table_dirty (Lisp_Object table)
+{
+  assert (!XCHAR_TABLE (table)->mirror_table_p);
+  XCHAR_TABLE (XCHAR_TABLE (table)->mirror_table)->dirty = 1;
+}
+
 void
 set_char_table_default (Lisp_Object table, Lisp_Object value)
 {
   Lisp_Char_Table *ct = XCHAR_TABLE (table);
   ct->default_ = value;
   if (ct->type == CHAR_TABLE_TYPE_SYNTAX)
-    update_syntax_table (table);
+    set_char_table_dirty (table);
 }
 
 static void
@@ -462,11 +469,17 @@
     ct->ascii[i] = value;
 #ifdef MULE
   for (i = 0; i < NUM_LEADING_BYTES; i++)
-    ct->level1[i] = value;
+    {
+      /* Don't get stymied when initting the table */
+      if (!EQ (ct->level1[i], Qnull_pointer) &&
+	  CHAR_TABLE_ENTRYP (ct->level1[i]))
+	free_lcrecord (ct->level1[i]);
+      ct->level1[i] = value;
+    }
 #endif /* MULE */
 
   if (ct->type == CHAR_TABLE_TYPE_SYNTAX)
-    update_syntax_table (wrap_char_table (ct));
+    set_char_table_dirty (wrap_char_table (ct));
 }
 
 DEFUN ("reset-char-table", Freset_char_table, 1, 1, 0, /*
@@ -576,19 +589,21 @@
 
   ct = alloc_lcrecord_type (Lisp_Char_Table, &lrecord_char_table);
   ct->type = ty;
+  obj = wrap_char_table (ct);
   if (ty == CHAR_TABLE_TYPE_SYNTAX)
     {
       /* Qgeneric not Qsyntax because a syntax table has a mirror table
 	 and we don't want infinite recursion */
       ct->mirror_table = Fmake_char_table (Qgeneric);
       set_char_table_default (ct->mirror_table, make_int (Spunct));
+      XCHAR_TABLE (ct->mirror_table)->mirror_table_p = 1;
+      XCHAR_TABLE (ct->mirror_table)->mirror_table = obj;
     }
   else
     ct->mirror_table = Qnil;
   ct->next_table = Qnil;
   ct->parent = Qnil;
   ct->default_ = Qnil;
-  obj = wrap_char_table (ct);
   if (ty == CHAR_TABLE_TYPE_SYNTAX)
     {
       ct->next_table = Vall_syntax_tables;
@@ -652,6 +667,8 @@
   ctnew->type = ct->type;
   ctnew->parent = ct->parent;
   ctnew->default_ = ct->default_;
+  ctnew->mirror_table_p = ct->mirror_table_p;
+  obj = wrap_char_table (ctnew);
 
   for (i = 0; i < NUM_ASCII_CHARS; i++)
     {
@@ -675,12 +692,14 @@
 
 #endif /* MULE */
 
-  if (CHAR_TABLEP (ct->mirror_table))
-    ctnew->mirror_table = Fcopy_char_table (ct->mirror_table);
+  if (!ct->mirror_table_p && CHAR_TABLEP (ct->mirror_table))
+    {
+      ctnew->mirror_table = Fcopy_char_table (ct->mirror_table);
+      XCHAR_TABLE (ctnew->mirror_table)->mirror_table = obj;
+    }
   else
     ctnew->mirror_table = ct->mirror_table;
   ctnew->next_table = Qnil;
-  obj = wrap_char_table (ctnew);
   if (ctnew->type == CHAR_TABLE_TYPE_SYNTAX)
     {
       ctnew->next_table = Vall_syntax_tables;
@@ -772,9 +791,9 @@
   map_char_table (from, range, copy_mapper, LISP_TO_VOID (to));
 }
 
-Lisp_Object
-get_range_char_table (struct chartab_range *range, Lisp_Object table,
-		      Lisp_Object multi)
+static Lisp_Object
+get_range_char_table_1 (struct chartab_range *range, Lisp_Object table,
+			Lisp_Object multi)
 {
   Lisp_Char_Table *ct = XCHAR_TABLE (table);
   Lisp_Object retval = Qnil;
@@ -863,6 +882,32 @@
   return retval;
 }
 
+Lisp_Object
+get_range_char_table (struct chartab_range *range, Lisp_Object table,
+		      Lisp_Object multi)
+{
+  if (range->type == CHARTAB_RANGE_CHAR)
+    return get_char_table (range->ch, table);
+  else
+    return get_range_char_table_1 (range, table, multi);
+}
+
+#ifdef ERROR_CHECK_TYPES
+
+/* Only exists so as not to trip an assert in get_char_table(). */
+Lisp_Object
+updating_mirror_get_range_char_table (struct chartab_range *range,
+				      Lisp_Object table,
+				      Lisp_Object multi)
+{
+  if (range->type == CHARTAB_RANGE_CHAR)
+    return get_char_table_1 (range->ch, table);
+  else
+    return get_range_char_table_1 (range, table, multi);
+}
+
+#endif /* ERROR_CHECK_TYPES */
+
 DEFUN ("get-range-char-table", Fget_range_char_table, 2, 3, 0, /*
 Find value for a range in CHAR-TABLE.
 If there is more than one value, return MULTI (defaults to nil).
@@ -986,8 +1031,7 @@
     {
     case CHARTAB_RANGE_ALL:
       fill_char_table (ct, val);
-      return; /* avoid the duplicate call to update_syntax_table() below,
-		 since fill_char_table() also did that. */
+      return; /* fill_char_table() recorded the table as dirty. */
 
 #ifdef MULE
     case CHARTAB_RANGE_CHARSET:
@@ -1006,6 +1050,8 @@
       else
 	{
 	  int lb = XCHARSET_LEADING_BYTE (range->charset) - MIN_LEADING_BYTE;
+	  if (CHAR_TABLE_ENTRYP (ct->level1[lb]))
+	    free_lcrecord (ct->level1[lb]);
 	  ct->level1[lb] = val;
 	}
       break;
@@ -1067,7 +1113,7 @@
     }
 
   if (ct->type == CHAR_TABLE_TYPE_SYNTAX)
-    update_syntax_table (wrap_char_table (ct));
+    set_char_table_dirty (wrap_char_table (ct));
 }
 
 DEFUN ("put-char-table", Fput_char_table, 3, 3, 0, /*
--- a/src/chartab.h	Fri Feb 14 07:54:29 2003 +0000
+++ b/src/chartab.h	Fri Feb 14 09:50:17 2003 +0000
@@ -1,7 +1,7 @@
 /* Declarations having to do with Mule char tables.
    Copyright (C) 1992 Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
-   Copyright (C) 2002 Ben Wing.
+   Copyright (C) 2002, 2003 Ben Wing.
 
 This file is part of XEmacs.
 
@@ -119,8 +119,12 @@
   enum char_table_type type;
 
   /* stuff used for syntax tables */
-  Lisp_Object mirror_table;
+  Lisp_Object mirror_table; /* points to mirror table for this table
+			       (a cache for quicker access), or a back
+			       pointer if MIRROR_TABLE_P. */
   Lisp_Object next_table; /* DO NOT mark through this. */
+  char dirty; /* nonzero if mirror dirty and needs updating. */
+  char mirror_table_p; /* nonzero if this is a mirror table. */
 };
 typedef struct Lisp_Char_Table Lisp_Char_Table;
 
@@ -140,7 +144,7 @@
 
 DECLARE_INLINE_HEADER (
 Lisp_Object
-get_char_table (Ichar ch, Lisp_Object table)
+get_char_table_1 (Ichar ch, Lisp_Object table)
 )
 {
   Lisp_Object retval;
@@ -165,6 +169,19 @@
     return ct->default_;
 }
 
+#ifdef ERROR_CHECK_TYPES
+DECLARE_INLINE_HEADER (
+Lisp_Object
+get_char_table (Ichar ch, Lisp_Object table)
+)
+{
+  assert (!XCHAR_TABLE (table)->mirror_table_p);
+  return get_char_table_1 (ch, table);
+}
+#else
+#define get_char_table(ch, table) get_char_table_1 (ch, table)
+#endif
+
 enum chartab_range_type
 {
   CHARTAB_RANGE_ALL,
@@ -195,6 +212,13 @@
 void prune_syntax_tables (void);
 Lisp_Object get_range_char_table (struct chartab_range *range,
 				  Lisp_Object table, Lisp_Object multi);
+#ifdef ERROR_CHECK_TYPES
+Lisp_Object updating_mirror_get_range_char_table (struct chartab_range *range,
+						  Lisp_Object table,
+						  Lisp_Object multi);
+#else
+#define updating_mirror_get_range_char_table get_range_char_table
+#endif
 void copy_char_table_range (Lisp_Object from, Lisp_Object to,
 			    struct chartab_range *range);
 int word_boundary_p (Ichar c1, Ichar c2);
--- a/src/font-lock.c	Fri Feb 14 07:54:29 2003 +0000
+++ b/src/font-lock.c	Fri Feb 14 09:50:17 2003 +0000
@@ -1,7 +1,7 @@
 /* Routines to compute the current syntactic context, for font-lock mode.
    Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
-   Copyright (C) 2002 Ben Wing.
+   Copyright (C) 2002, 2003 Ben Wing.
 
 This file is part of XEmacs.
 
@@ -562,7 +562,7 @@
             else if (context_cache.context == context_none)
 	      {
 		Lisp_Object stringtermobj =
-		  syntax_match (scache->current_syntax_table, c);
+		  syntax_match (scache->syntax_table, c);
 		Ichar stringterm;
 
 		if (CHARP (stringtermobj))
--- a/src/syntax.c	Fri Feb 14 07:54:29 2003 +0000
+++ b/src/syntax.c	Fri Feb 14 09:50:17 2003 +0000
@@ -1,7 +1,7 @@
 /* XEmacs routines to deal with syntax tables; also word and list parsing.
    Copyright (C) 1985-1994 Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
-   Copyright (C) 2001, 2002 Ben Wing.
+   Copyright (C) 2001, 2002, 2003 Ben Wing.
 
 This file is part of XEmacs.
 
@@ -86,6 +86,9 @@
 
 Lisp_Object Vtemp_table_for_use_updating_syntax_tables;
 
+/* A value that is guaranteed not be in a syntax table. */
+Lisp_Object Vbogus_syntax_table_value;
+
 static void syntax_cache_table_was_changed (struct buffer *buf);
 
 /* This is the internal form of the parse state used in parse-partial-sexp.  */
@@ -271,7 +274,9 @@
   cache->object = object;
   cache->buffer = buffer;
   cache->no_syntax_table_prop = 1;
-  cache->current_syntax_table =
+  cache->syntax_table =
+    BUFFER_SYNTAX_TABLE (cache->buffer);
+  cache->mirror_table =
     BUFFER_MIRROR_SYNTAX_TABLE (cache->buffer);
   cache->start = Qnil;
   cache->end = Qnil;
@@ -308,6 +313,9 @@
       if (!(from >= cache->prev_change && from < cache->next_change))
 	update_syntax_cache (cache, from, count);
     }
+#ifdef NOT_WORTH_THE_EFFORT
+  update_mirror_syntax_if_dirty (cache->mirror_table);
+#endif /* NOT_WORTH_THE_EFFORT */
   return cache;
 }
 
@@ -317,6 +325,21 @@
   return setup_syntax_cache (NULL, wrap_buffer (buffer), buffer, from, count);
 }
 
+static const struct memory_description syntax_cache_description_1 [] = {
+  { XD_LISP_OBJECT, offsetof (struct syntax_cache, object) },
+  { XD_LISP_OBJECT, offsetof (struct syntax_cache, buffer) },
+  { XD_LISP_OBJECT, offsetof (struct syntax_cache, syntax_table) },
+  { XD_LISP_OBJECT, offsetof (struct syntax_cache, mirror_table) },
+  { XD_LISP_OBJECT, offsetof (struct syntax_cache, start) },
+  { XD_LISP_OBJECT, offsetof (struct syntax_cache, end) },
+  { XD_END }
+};
+
+const struct sized_memory_description syntax_cache_description = {
+  sizeof (struct syntax_cache),
+  syntax_cache_description_1
+};
+
 void
 mark_buffer_syntax_cache (struct buffer *buf)
 {
@@ -326,7 +349,8 @@
   mark_object (cache->object);
   if (cache->buffer)
     mark_object (wrap_buffer (cache->buffer));
-  mark_object (cache->current_syntax_table);
+  mark_object (cache->syntax_table);
+  mark_object (cache->mirror_table);
   mark_object (cache->start);
   mark_object (cache->end);
 }
@@ -351,7 +375,8 @@
   cache->object = wrap_buffer (buf);
   cache->buffer = buf;
   cache->no_syntax_table_prop = 1;
-  cache->current_syntax_table = BUFFER_MIRROR_SYNTAX_TABLE (cache->buffer);
+  cache->syntax_table = BUFFER_SYNTAX_TABLE (cache->buffer);
+  cache->mirror_table = BUFFER_MIRROR_SYNTAX_TABLE (cache->buffer);
   cache->start = Fmake_marker ();
   cache->end = Fmake_marker ();
   reset_buffer_cache_range (cache, cache->object);
@@ -370,8 +395,12 @@
 {
   struct syntax_cache *cache = buf->syntax_cache;
   if (cache->no_syntax_table_prop)
-    cache->current_syntax_table =
-      BUFFER_MIRROR_SYNTAX_TABLE (buf);
+    {
+      cache->syntax_table =
+	BUFFER_SYNTAX_TABLE (buf);
+      cache->mirror_table =
+	BUFFER_MIRROR_SYNTAX_TABLE (buf);
+    }
 }
 
 /* The syntax-table property on the range covered by EXTENT may be changing,
@@ -495,9 +524,12 @@
   if (!NILP (Fsyntax_table_p (tmp_table)))
     {
       cache->use_code = 0;
-      cache->current_syntax_table =
-	XCHAR_TABLE (tmp_table)->mirror_table;
+      cache->syntax_table = tmp_table;
+      cache->mirror_table = XCHAR_TABLE (tmp_table)->mirror_table;
       cache->no_syntax_table_prop = 0;
+#ifdef NOT_WORTH_THE_EFFORT
+      update_mirror_syntax_if_dirty (cache->mirror_table);
+#endif /* NOT_WORTH_THE_EFFORT */
     } 
   else if (CONSP (tmp_table) && INTP (XCAR (tmp_table)))
     {
@@ -509,8 +541,11 @@
     {
       cache->use_code = 0;
       cache->no_syntax_table_prop = 1;
-      cache->current_syntax_table =
-	BUFFER_MIRROR_SYNTAX_TABLE (cache->buffer);
+      cache->syntax_table = BUFFER_SYNTAX_TABLE (cache->buffer);
+      cache->mirror_table = BUFFER_MIRROR_SYNTAX_TABLE (cache->buffer);
+#ifdef NOT_WORTH_THE_EFFORT
+      update_mirror_syntax_if_dirty (cache->mirror_table);
+#endif /* NOT_WORTH_THE_EFFORT */
     }
 }
 
@@ -1407,7 +1442,7 @@
 		    /* XEmacs change: call syntax_match on character */
 		    Ichar ch = BUF_FETCH_CHAR (buf, from - 1);
 		    Lisp_Object stermobj =
-		      syntax_match (scache->current_syntax_table, ch);
+		      syntax_match (scache->syntax_table, ch);
 
 		if (CHARP (stermobj))
 		  stringterm = XCHAR (stermobj);
@@ -1587,7 +1622,7 @@
 		/* XEmacs change: call syntax_match() on character */
                 Ichar ch = BUF_FETCH_CHAR (buf, from);
 		    Lisp_Object stermobj =
-		      syntax_match (scache->current_syntax_table, ch);
+		      syntax_match (scache->syntax_table, ch);
 
 		if (CHARP (stermobj))
 		  stringterm = XCHAR (stermobj);
@@ -2012,7 +2047,7 @@
 	      /* XEmacs change: call syntax_match() on character */
 	      Ichar ch = BUF_FETCH_CHAR (buf, from - 1);
 	      Lisp_Object stermobj =
-		syntax_match (scache->current_syntax_table, ch);
+		syntax_match (scache->syntax_table, ch);
 
 	      if (CHARP (stermobj))
 		state.instring = XCHAR (stermobj);
@@ -2181,9 +2216,10 @@
 
 /* Updating of the mirror syntax table.
 
-   Each syntax table has a corresponding mirror table in it.
-   Whenever we make a change to a syntax table, we call
-   update_syntax_table() on it.
+   Each syntax table has a corresponding mirror table in it.  Whenever we
+   make a change to a syntax table, we set a dirty flag.  When accessing a
+   value from the mirror table and the table is dirty, we call
+   update_syntax_table() to clean it up.
 
    #### We really only need to map over the changed range.
 
@@ -2208,41 +2244,32 @@
   return 0;
 }
 
-struct cinap
-{
-  Lisp_Object mirrortab;
-  Lisp_Object bogus;
-};
-
 static int
 copy_if_not_already_present (struct chartab_range *range, Lisp_Object table,
 			     Lisp_Object val, void *arg)
 {
-  struct cinap *a = (struct cinap *) arg;
-
+  Lisp_Object mirrortab = VOID_TO_LISP (arg);
   if (CONSP (val))
     val = XCAR (val);
   if (SYNTAX_FROM_CODE (XINT (val)) != Sinherit)
     {
       Lisp_Object existing =
-	get_range_char_table (range, a->mirrortab, a->bogus);
+	updating_mirror_get_range_char_table (range, mirrortab,
+					      Vbogus_syntax_table_value);
       if (NILP (existing))
 	/* nothing at all */
-	put_char_table (a->mirrortab, range, val);
-      else if (!EQ (existing, a->bogus))
+	put_char_table (mirrortab, range, val);
+      else if (!EQ (existing, Vbogus_syntax_table_value))
 	/* full */
 	;
       else
 	{
 	  Freset_char_table (Vtemp_table_for_use_updating_syntax_tables);
 	  copy_char_table_range
-	    (a->mirrortab,
-	     Vtemp_table_for_use_updating_syntax_tables,
-	     range);
-	  put_char_table (a->mirrortab, range, val);
+	    (mirrortab, Vtemp_table_for_use_updating_syntax_tables, range);
+	  put_char_table (mirrortab, range, val);
 	  copy_char_table_range
-	    (Vtemp_table_for_use_updating_syntax_tables,
-	     a->mirrortab, range);
+	    (Vtemp_table_for_use_updating_syntax_tables, mirrortab, range);
 	}
     }
 
@@ -2255,8 +2282,10 @@
   struct chartab_range range;
   Lisp_Object mirrortab = XCHAR_TABLE (table)->mirror_table;
 
+  assert (!XCHAR_TABLE (table)->mirror_table_p);
   range.type = CHARTAB_RANGE_ALL;
   Freset_char_table (mirrortab);
+
   /* First, copy the tables values other than inherit into the mirror
      table.  Then, for tables other than the standard syntax table, map
      over the standard table, copying values into the mirror table only if
@@ -2268,19 +2297,11 @@
   /* second clause catches bootstrapping problems when initializing the
      standard syntax table */
   if (!EQ (table, Vstandard_syntax_table) && !NILP (Vstandard_syntax_table))
-    {
-      struct cinap cinap;
-      struct gcpro gcpro1;
-      cinap.mirrortab = mirrortab;
-      /* Something that won't be in the table. */
-      cinap.bogus = make_float (0.0);
-      GCPRO1 (cinap.bogus);
-      map_char_table (Vstandard_syntax_table, &range,
-		      copy_if_not_already_present, &cinap);
-      UNGCPRO;
-    }
+    map_char_table (Vstandard_syntax_table, &range,
+		    copy_if_not_already_present, LISP_TO_VOID (mirrortab));
   /* The resetting made the default be Qnil.  Put it back to Spunct. */
   set_char_table_default (mirrortab, make_int (Spunct));
+  XCHAR_TABLE (mirrortab)->dirty = 0;
 }
 
 /* Called from chartab.c when a change is made to a syntax table.
@@ -2291,7 +2312,9 @@
 void
 update_syntax_table (Lisp_Object table)
 {
-  if (EQ (table, Vstandard_syntax_table))
+  Lisp_Object nonmirror = XCHAR_TABLE (table)->mirror_table;
+  assert (XCHAR_TABLE (table)->mirror_table_p);
+  if (EQ (nonmirror, Vstandard_syntax_table))
     {
       Lisp_Object syntab;
 
@@ -2300,7 +2323,7 @@
 	update_just_this_syntax_table (syntab);
     }
   else
-    update_just_this_syntax_table (table);
+    update_just_this_syntax_table (nonmirror);
 }
 
 
@@ -2365,6 +2388,9 @@
   words_include_escapes = 0;
 
   no_quit_in_re_search = 0;
+
+  Vbogus_syntax_table_value = make_float (0.0);
+  staticpro (&Vbogus_syntax_table_value);
 }
 
 static void
--- a/src/syntax.h	Fri Feb 14 07:54:29 2003 +0000
+++ b/src/syntax.h	Fri Feb 14 09:50:17 2003 +0000
@@ -1,6 +1,6 @@
 /* Declarations having to do with XEmacs syntax tables.
    Copyright (C) 1985, 1992, 1993 Free Software Foundation, Inc.
-   Copyright (C) 2002 Ben Wing.
+   Copyright (C) 2002, 2003 Ben Wing.
 
 This file is part of XEmacs.
 
@@ -72,9 +72,43 @@
 enum syntaxcode charset_syntax (struct buffer *buf, Lisp_Object charset,
 				int *multi_p_out);
 
+void update_syntax_table (Lisp_Object table);
+
+DECLARE_INLINE_HEADER (
+void
+update_mirror_syntax_if_dirty (Lisp_Object table)
+)
+{
+  if (XCHAR_TABLE (table)->dirty)
+    update_syntax_table (table);
+}
+
 /* Return the syntax code for a particular character and mirror table. */
 
-#define SYNTAX_CODE(table, c) XINT (get_char_table (c, table))
+DECLARE_INLINE_HEADER (
+enum syntaxcode
+SYNTAX_CODE (Lisp_Object table, Ichar c)
+)
+{
+  type_checking_assert (XCHAR_TABLE (table)->mirror_table_p);
+  update_mirror_syntax_if_dirty (table);
+  return (enum syntaxcode) XINT (get_char_table_1 (c, table));
+}
+
+#ifdef NOT_WORTH_THE_EFFORT
+
+/* Same but skip the dirty check. */
+
+DECLARE_INLINE_HEADER (
+enum syntaxcode
+SYNTAX_CODE_1 (Lisp_Object table, Ichar c)
+)
+{
+  type_checking_assert (XCHAR_TABLE (table)->mirror_table_p);
+  return (enum syntaxcode) XINT (get_char_table_1 (c, table));
+}
+
+#endif /* NOT_WORTH_THE_EFFORT */
 
 #define SYNTAX_FROM_CODE(code) ((enum syntaxcode) ((code) & 0177))
 
@@ -246,8 +280,6 @@
 
 extern int no_quit_in_re_search;
 
-void update_syntax_table (Lisp_Object table);
-
 
 /****************************** syntax caches ********************************/
 
@@ -264,8 +296,8 @@
 struct syntax_cache
 {
   int use_code;				/* Whether to use syntax_code or
-					   current_syntax_table.  This is
-					   set depending on whether the
+					   syntax_table.  This is set
+					   depending on whether the
 					   syntax-table property is a
 					   syntax table or a syntax
 					   code. */
@@ -286,7 +318,8 @@
 					   OBJECT is a buffer, this will
 					   always be the same buffer. */
   int syntax_code;			/* Syntax code of current char. */
-  Lisp_Object current_syntax_table;	/* Syntax table for current pos. */
+  Lisp_Object syntax_table;		/* Syntax table for current pos. */
+  Lisp_Object mirror_table;		/* Mirror table for this table. */
   Lisp_Object start, end;		/* Markers to keep track of the
 					   known region in a buffer.
 					   Formerly we used an internal
@@ -300,6 +333,8 @@
 					   change. */
 };
 
+extern const struct sized_memory_description syntax_cache_description;
+
 /* Note that the external interface to the syntax-cache uses charpos's, but
    intnernally we use bytepos's, for speed. */
 
@@ -348,7 +383,23 @@
 
 #define SYNTAX_CODE_FROM_CACHE(cache, c)				\
   ((cache)->use_code ? (cache)->syntax_code				\
-   : SYNTAX_CODE ((cache)->current_syntax_table, c))
+   : SYNTAX_CODE ((cache)->mirror_table, c))
+
+#ifdef NOT_WORTH_THE_EFFORT
+/* If we really cared about the theoretical performance hit of the dirty
+   check in SYNTAX_CODE, we could use SYNTAX_CODE_1 and endeavor to always
+   keep the mirror table clean, e.g. by checking for dirtiness at the time
+   we set up the syntax cache.  There are lots of potential problems, of
+   course -- incomplete understanding of the possible pathways into the
+   code, with some that are bypassing the setups, Lisp code being executed
+   in the meantime that could change things (e.g. QUIT is called in many
+   functions and could execute arbitrary Lisp very easily), etc.  The QUIT
+   problem is the biggest one, probably, and one of the main reasons it's
+   probably just not worth it. */
+#define SYNTAX_CODE_FROM_CACHE(cache, c)				\
+  ((cache)->use_code ? (cache)->syntax_code				\
+   : SYNTAX_CODE_1 ((cache)->mirror_table, c))
+#endif
 
 
 /***************************** syntax code macros ****************************/