diff src/opaque.c @ 412:697ef44129c6 r21-2-14

Import from CVS: tag r21-2-14
author cvs
date Mon, 13 Aug 2007 11:20:41 +0200
parents 2f8bb876ab1d
children 41dbb7a9d5f2
line wrap: on
line diff
--- a/src/opaque.c	Mon Aug 13 11:19:22 2007 +0200
+++ b/src/opaque.c	Mon Aug 13 11:20:41 2007 +0200
@@ -32,31 +32,79 @@
    OPAQUE OBJECTS SHOULD NEVER ESCAPE TO THE LISP LEVEL.  Some code
    depends on this.  As such, opaque objects are a generalization
    of the Qunbound marker.
+
+   "Opaque lists" are used to keep track of lots of opaque objects
+   of a particular size so that they can be efficiently "freed" and
+   re-used again without actually entering the Lisp allocation system
+   (and consequently doing a malloc()).
  */
 
 #include <config.h>
 #include "lisp.h"
 #include "opaque.h"
+#include <stddef.h>
 
+Lisp_Object Qopaquep;
+
+static int in_opaque_list_marking;
+
+/* Holds freed opaque objects created with make_opaque_ptr().
+   We do this quite often so it's a noticeable win if we don't
+   create GC junk. */
 Lisp_Object Vopaque_ptr_free_list;
 
+static Lisp_Object
+mark_opaque (Lisp_Object obj, void (*markobj) (Lisp_Object))
+{
+  Lisp_Opaque *p = XOPAQUE (obj);
+  /* Egcs 1.1.1 sometimes crashes on INTP (p->size_or_chain) */
+  Lisp_Object size_or_chain = p->size_or_chain;
+#ifdef ERROR_CHECK_GC
+  if (!in_opaque_list_marking)
+    /* size is non-int for objects on an opaque free list.  We sure
+       as hell better not be marking any of these objects unless
+       we're marking an opaque list. */
+    assert (GC_INTP (size_or_chain));
+  else
+    /* marking an opaque on the free list doesn't do any recursive
+       markings, so we better not have non-freed opaques on a free
+       list. */
+    assert (!GC_INTP (size_or_chain));
+#endif
+  if (GC_INTP (size_or_chain) && OPAQUE_MARKFUN (p))
+    return OPAQUE_MARKFUN (p) (obj, markobj);
+  else
+    return size_or_chain;
+}
+
 /* Should never, ever be called. (except by an external debugger) */
 static void
 print_opaque (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
 {
-  const Lisp_Opaque *p = XOPAQUE (obj);
+  CONST Lisp_Opaque *p = XOPAQUE (obj);
+  /* Egcs 1.1.1 sometimes crashes on INTP (p->size_or_chain) */
+  Lisp_Object size_or_chain = p->size_or_chain;
   char buf[200];
+  char size_buf[50];
 
-  sprintf (buf, "#<INTERNAL OBJECT (XEmacs bug?) (opaque, size=%lu) 0x%lx>",
-	   (long)(p->size), (unsigned long) p);
+  if (INTP (size_or_chain))
+    sprintf (size_buf, "size=%lu", (unsigned long) OPAQUE_SIZE (p));
+  else
+    sprintf (size_buf, "freed");
+
+  sprintf (buf, "#<INTERNAL OBJECT (XEmacs bug?) (opaque, %s) 0x%lx>",
+	   size_buf, (unsigned long) p);
   write_c_string (buf, printcharfun);
 }
 
 static size_t
-sizeof_opaque (const void *header)
+sizeof_opaque (CONST void *header)
 {
-  const Lisp_Opaque *p = (const Lisp_Opaque *) header;
-  return offsetof (Lisp_Opaque, data) + p->size;
+  CONST Lisp_Opaque *p = (CONST Lisp_Opaque *) header;
+  /* Egcs 1.1.1 sometimes crashes on INTP (p->size_or_chain) */
+  Lisp_Object size_or_chain = p->size_or_chain;
+  return offsetof (Lisp_Opaque, data)
+    + (GC_INTP (size_or_chain) ? XINT (size_or_chain) : 0);
 }
 
 /* Return an opaque object of size SIZE.
@@ -64,11 +112,12 @@
    If DATA is OPAQUE_UNINIT, the object's data is uninitialized.
    Else the object's data is initialized by copying from DATA. */
 Lisp_Object
-make_opaque (const void *data, size_t size)
+make_opaque (size_t size, CONST void *data)
 {
   Lisp_Opaque *p = (Lisp_Opaque *)
     alloc_lcrecord (offsetof (Lisp_Opaque, data) + size, &lrecord_opaque);
-  p->size = size;
+  p->markfun = 0;
+  p->size_or_chain = make_int (size);
 
   if (data == OPAQUE_CLEAR)
     memset (p->data, '\0', size);
@@ -89,9 +138,21 @@
 static int
 equal_opaque (Lisp_Object obj1, Lisp_Object obj2, int depth)
 {
-  size_t size;
-  return ((size = XOPAQUE_SIZE (obj1)) == XOPAQUE_SIZE (obj2) &&
-	  !memcmp (XOPAQUE_DATA (obj1), XOPAQUE_DATA (obj2), size));
+#ifdef DEBUG_XEMACS
+  {
+    /* Egcs 1.1.1 sometimes crashes on INTP (p->size_or_chain) */
+    Lisp_Object size_or_chain_1 = XOPAQUE (obj1)->size_or_chain;
+    Lisp_Object size_or_chain_2 = XOPAQUE (obj2)->size_or_chain;
+    assert (INTP (size_or_chain_1));
+    assert (INTP (size_or_chain_2));
+    assert (!XOPAQUE_MARKFUN (obj1) && !XOPAQUE_MARKFUN (obj2));
+  }
+#endif
+  {
+    size_t size;
+    return ((size = XOPAQUE_SIZE (obj1)) == XOPAQUE_SIZE (obj2) &&
+	    !memcmp (XOPAQUE_DATA (obj1), XOPAQUE_DATA (obj2), size));
+  }
 }
 
 /* This will not work correctly for opaques with subobjects! */
@@ -99,59 +160,102 @@
 static unsigned long
 hash_opaque (Lisp_Object obj, int depth)
 {
+#ifdef DEBUG_XEMACS
+  {
+    /* Egcs 1.1.1 sometimes crashes on INTP (p->size_or_chain) */
+    Lisp_Object size_or_chain = XOPAQUE (obj)->size_or_chain;
+    assert (INTP (size_or_chain));
+    assert (!XOPAQUE_MARKFUN (obj));
+  }
+#endif
   if (XOPAQUE_SIZE (obj) == sizeof (unsigned long))
     return *((unsigned long *) XOPAQUE_DATA (obj));
   else
     return memory_hash (XOPAQUE_DATA (obj), XOPAQUE_SIZE (obj));
 }
 
-static const struct lrecord_description opaque_description[] = {
-  { XD_END }
-};
+DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("opaque", opaque,
+					mark_opaque, print_opaque, 0,
+					equal_opaque, hash_opaque,
+					sizeof_opaque, Lisp_Opaque);
+
+static Lisp_Object
+mark_opaque_list (Lisp_Object obj, void (*markobj) (Lisp_Object))
+{
+  in_opaque_list_marking++;
+  markobj (XOPAQUE_LIST (obj)->free);
+  in_opaque_list_marking--;
+  return Qnil;
+}
+
+Lisp_Object
+make_opaque_list (size_t size,
+		  Lisp_Object (*markfun) (Lisp_Object obj,
+					  void (*markobj) (Lisp_Object)))
+{
+  Lisp_Object val;
+  Lisp_Opaque_List *p =
+    alloc_lcrecord_type (Lisp_Opaque_List, &lrecord_opaque_list);
+
+  p->markfun = markfun;
+  p->size = size;
+  p->free = Qnil;
+  XSETOPAQUE_LIST (val, p);
+  return val;
+}
+
+DEFINE_LRECORD_IMPLEMENTATION ("opaque-list", opaque_list,
+			       mark_opaque_list, internal_object_printer,
+			       0, 0, 0, Lisp_Opaque_List);
 
-DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("opaque", opaque,
-					0, print_opaque, 0,
-					equal_opaque, hash_opaque,
-					opaque_description,
-					sizeof_opaque, Lisp_Opaque);
+Lisp_Object
+allocate_managed_opaque (Lisp_Object opaque_list, CONST void *data)
+{
+  Lisp_Opaque_List *li = XOPAQUE_LIST (opaque_list);
+  Lisp_Object val;
+
+  if (!NILP (li->free))
+    {
+      val = li->free;
+      li->free = XOPAQUE (val)->size_or_chain;
+#ifdef ERROR_CHECK_GC
+      assert (NILP (li->free) || OPAQUEP (li->free));
+#endif
+      XOPAQUE (val)->size_or_chain = make_int (li->size);
+      if (data)
+	memcpy (XOPAQUE (val)->data, data, li->size);
+      else
+	memset (XOPAQUE (val)->data, 0, li->size);
+    }
+  else
+    val = make_opaque (li->size, data);
+  XOPAQUE (val)->markfun = li->markfun;
+  return val;
+}
+
+void
+free_managed_opaque (Lisp_Object opaque_list, Lisp_Object opaque)
+{
+  Lisp_Opaque_List *li = XOPAQUE_LIST (opaque_list);
+
+#ifdef ERROR_CHECK_GC
+  {
+    /* Egcs 1.1.1 sometimes crashes on INTP (p->size_or_chain) */
+    Lisp_Object size_or_chain = XOPAQUE (opaque)->size_or_chain;
+    assert (INTP (size_or_chain));
+  }
+#endif
+  XOPAQUE (opaque)->size_or_chain = li->free;
+  li->free = opaque;
+}
 
 /* stuff to handle opaque pointers */
 
-/* Should never, ever be called. (except by an external debugger) */
-static void
-print_opaque_ptr (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
-{
-  const Lisp_Opaque_Ptr *p = XOPAQUE_PTR (obj);
-  char buf[200];
-
-  sprintf (buf, "#<INTERNAL OBJECT (XEmacs bug?) (opaque-ptr, adr=0x%lx) 0x%lx>",
-	   (long)(p->ptr), (unsigned long) p);
-  write_c_string (buf, printcharfun);
-}
-
-static int
-equal_opaque_ptr (Lisp_Object obj1, Lisp_Object obj2, int depth)
+Lisp_Object
+make_opaque_ptr (CONST void *val)
 {
-  return (XOPAQUE_PTR (obj1)->ptr == XOPAQUE_PTR (obj2)->ptr);
-}
-
-static unsigned long
-hash_opaque_ptr (Lisp_Object obj, int depth)
-{
-  return (unsigned long) XOPAQUE_PTR (obj)->ptr;
-}
-
-DEFINE_LRECORD_IMPLEMENTATION ("opaque-ptr", opaque_ptr,
-			       0, print_opaque_ptr, 0,
-			       equal_opaque_ptr, hash_opaque_ptr, 0,
-			       Lisp_Opaque_Ptr);
-
-Lisp_Object
-make_opaque_ptr (void *val)
-{
-  Lisp_Object res = allocate_managed_lcrecord(Vopaque_ptr_free_list);
-  set_opaque_ptr (res, val);
-  return res;
+  return allocate_managed_opaque (Vopaque_ptr_free_list,
+				  (CONST void *) &val);
 }
 
 /* Be very very careful with this.  Same admonitions as with
@@ -160,21 +264,18 @@
 void
 free_opaque_ptr (Lisp_Object ptr)
 {
-  free_managed_lcrecord (Vopaque_ptr_free_list, ptr);
+  free_managed_opaque (Vopaque_ptr_free_list, ptr);
 }
 
-void
-reinit_opaque_once_early (void)
+Lisp_Object
+make_opaque_long (long val)
 {
-  Vopaque_ptr_free_list = make_lcrecord_list (sizeof (Lisp_Opaque_Ptr), &lrecord_opaque_ptr);
-  staticpro_nodump (&Vopaque_ptr_free_list);
+  return make_opaque (sizeof (val), (void *) &val);
 }
 
 void
 init_opaque_once_early (void)
 {
-  INIT_LRECORD_IMPLEMENTATION (opaque);
-  INIT_LRECORD_IMPLEMENTATION (opaque_ptr);
-
-  reinit_opaque_once_early ();
+  Vopaque_ptr_free_list = make_opaque_list (sizeof (void *), 0);
+  staticpro (&Vopaque_ptr_free_list);
 }