changeset 888:201c016cfc12

[xemacs-hg @ 2002-06-28 14:24:07 by michaels] 2002-06-27 Mike Sperber <mike@xemacs.org> * data.c (prune_weak_boxes): Rewrite for better readability. 2002-06-23 Martin Köbele <martin@mkoebele.de> Jens Müller <jmueller@informatik.uni-tuebingen.de> Mike Sperber <mike@xemacs.org> * lrecord.h (lrecord_type): add lrecord_type_ephemeron to lrecord_type enumeration. * lisp.h (XEPHEMERON): (XEPHEMERON_REF): (XEPHEMERON_NEXT): (XEPHEMERON_FINALIZER): (XSET_EPHEMERON_NEXT): (XSET_EPHEMERON_VALUE): (XSET_EPHEMERON_KEY): (wrap_ephemeron): (EPHEMERONP): (CHECK_EPHEMERON): (CONCHECK_EPHEMERON): (struct ephemeron): Add representation of ephemerons. * alloc.c (garbage_collect_1): (finish_marking_ephemerons): (prune_ephemerons): Call. * data.c: (finish_marking_ephemerons): (prune_ephemerons): (mark_ephemeron): (print_ephemeron): (ephemeron_equal) (ephemeron_hash):: (make_ephemeron): (Fmake_ephemeron): (Fephemeronp): (Fephemeron_ref): (syms_of_data): (vars_of_data): Add implementation of ephemerons
author michaels
date Fri, 28 Jun 2002 14:24:08 +0000
parents ccc3177ef10b
children aa5a731873df
files src/data.c src/lisp.h src/lrecord.h
diffstat 3 files changed, 266 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/data.c	Fri Jun 28 14:21:41 2002 +0000
+++ b/src/data.c	Fri Jun 28 14:24:08 2002 +0000
@@ -2004,6 +2004,7 @@
   return new_list;
 }
 
+
 /************************************************************************/
 /*                              weak boxes                              */
 /************************************************************************/
@@ -2014,24 +2015,38 @@
 prune_weak_boxes (void)
 {
   Lisp_Object rest, prev = Qnil;
+  int removep = 0;
 
   for (rest = Vall_weak_boxes;
        !NILP(rest);
        rest = XWEAK_BOX (rest)->next_weak_box)
     {
       if (! (marked_p (rest)))
-	/* This weak box itself is garbage.  Remove it from the list. */
-	if (NILP (prev))
-	  Vall_weak_boxes = XWEAK_BOX (rest)->next_weak_box;
-	else
-	  XWEAK_BOX (prev)->next_weak_box = XWEAK_BOX (rest)->next_weak_box;
-      else if (!marked_p(XWEAK_BOX (rest)->value))
-	XSET_WEAK_BOX (rest, Qnil);
+	/* This weak box itself is garbage. */
+	removep = 1;
+
+       if (! marked_p (XWEAK_BOX (rest)->value))
+	 {
+	   XSET_WEAK_BOX (rest, Qnil);
+	   removep = 1;
+	 }
+
+       if (removep)
+	 {
+	   /* Remove weak box from list. */
+	   if (NILP (prev))
+	     Vall_weak_boxes = XWEAK_BOX (rest)->next_weak_box;
+	   else
+	     XWEAK_BOX (prev)->next_weak_box = XWEAK_BOX (rest)->next_weak_box;
+	   removep = 0;
+	 }
+       else
+	 prev = rest;
     }
 }
 
 static Lisp_Object
-mark_weak_box (Lisp_Object obj) 
+mark_weak_box (Lisp_Object obj)
 {
   return Qnil;
 }
@@ -2047,18 +2062,18 @@
 static int
 weak_box_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
 {
-  struct weak_box *b1 = XWEAK_BOX (obj1);
-  struct weak_box *b2 = XWEAK_BOX (obj2);
+  struct weak_box *wb1 = XWEAK_BOX (obj1);
+  struct weak_box *wb2 = XWEAK_BOX (obj2);
 
-  return (internal_equal (b1->value, b2->value, depth + 1));
+  return (internal_equal (wb1->value, wb2->value, depth + 1));
 }
 
 static Hashcode
 weak_box_hash (Lisp_Object obj, int depth)
 {
-  struct weak_box *b = XWEAK_BOX (obj);
+  struct weak_box *wb = XWEAK_BOX (obj);
 
-  return internal_hash (b->value, depth + 1);
+  return internal_hash (wb->value, depth + 1);
 }
 
 Lisp_Object
@@ -2076,9 +2091,9 @@
   return result;
 }
 
-static const struct lrecord_description weak_box_description[] = { 
+static const struct lrecord_description weak_box_description[] = {
   { XD_LO_LINK, offsetof (struct weak_box, value) },
-  { XD_END} 
+  { XD_END}
 };
 
 DEFINE_LRECORD_IMPLEMENTATION ("weak_box", weak_box,
@@ -2103,9 +2118,9 @@
 Return the contents of weak box WEAK-BOX.
 If the contents have been GCed, return NIL.
 */
-       (box))
+       (wb))
 {
-  return XWEAK_BOX(box)->value;
+  return XWEAK_BOX (wb)->value;
 }
 
 DEFUN ("weak-box-p", Fweak_boxp, 1, 1, 0, /*
@@ -2116,6 +2131,187 @@
   return WEAK_BOXP (object) ? Qt : Qnil;
 }
 
+/************************************************************************/
+/*                              ephemerons                              */
+/************************************************************************/
+
+static Lisp_Object Vall_ephemerons; /* Gemarke es niemals ever!!! */
+static Lisp_Object Vfinalize_list;
+
+int
+finish_marking_ephemerons(void)
+{
+  Lisp_Object rest;
+  int did_mark = 0;
+
+  for (rest = Vall_ephemerons;
+       !NILP (rest);
+       rest = XEPHEMERON_NEXT (rest))
+    {
+      if (marked_p (rest) && ! marked_p (XEPHEMERON (rest)->cons_chain))
+	{
+	  MARK_CONS (XCONS (XEPHEMERON (rest)->cons_chain));
+	  mark_object (XCAR (XEPHEMERON (rest)->cons_chain));
+	  did_mark = 1;
+	}
+    }
+  return did_mark;
+}
+
+void
+prune_ephemerons(void)
+{
+  int removep = 0;
+  Lisp_Object rest = Vall_ephemerons, next, prev = Qnil;
+
+  while (! NILP (rest))
+    {
+      next = XEPHEMERON_NEXT (rest);
+
+      if (marked_p (rest))
+	/* The ephemeron itself is live ... */
+	{
+	  if (! marked_p(XEPHEMERON (rest)->key))
+	    /* ... but its key is garbage */
+	    {
+	      removep = 1;
+	      XSET_EPHEMERON_VALUE (rest, Qnil);
+	      if (! NILP (XEPHEMERON_FINALIZER (rest)))
+		/* Register the finalizer */
+		{
+		  XSET_EPHEMERON_NEXT (rest, Vfinalize_list);
+		  Vfinalize_list = XEPHEMERON (rest)->cons_chain;
+		}
+	    }
+	}
+      else
+	/* The ephemeron itself is dead. */
+	removep = 1;
+
+      if (removep)
+	{
+	  /* Remove it from the list. */
+	  if (NILP (prev))
+	    Vall_ephemerons = next;
+	  else
+	    XSET_EPHEMERON_NEXT (prev, next);
+	  removep = 0;
+	}
+      else
+	prev = rest;
+
+      rest = next;
+    }
+}
+
+Lisp_Object
+zap_finalize_list(void)
+{
+  Lisp_Object finalizers = Vfinalize_list;
+
+  Vfinalize_list = Qnil;
+
+  return finalizers;
+}
+
+static Lisp_Object
+mark_ephemeron (Lisp_Object obj)
+{
+  return Qnil;
+}
+
+static void
+print_ephemeron (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
+{
+  if (print_readably)
+    printing_unreadable_object ("#<ephemeron>");
+  write_fmt_string (printcharfun, "#<ephemeron>");
+}
+
+static int
+ephemeron_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
+{
+  return
+    internal_equal (XEPHEMERON_REF (obj1), XEPHEMERON_REF(obj2), depth + 1);
+}
+
+static Hashcode
+ephemeron_hash(Lisp_Object obj, int depth)
+{
+  return internal_hash (XEPHEMERON_REF (obj), depth + 1);
+}
+
+Lisp_Object
+make_ephemeron(Lisp_Object key, Lisp_Object value, Lisp_Object finalizer)
+{
+  Lisp_Object result, temp = Qnil;
+  struct gcpro gcpro1, gcpro2;
+
+  struct ephemeron *eph =
+    alloc_lcrecord_type (struct ephemeron, &lrecord_ephemeron);
+
+  eph->key = Qnil;
+  eph->cons_chain = Qnil;
+  eph->value = Qnil;
+
+  result = wrap_ephemeron(eph);
+  GCPRO2 (result, temp);
+
+  eph->key = key;
+  temp = Fcons(value, finalizer);
+  eph->cons_chain = Fcons(temp, Vall_ephemerons);
+  eph->value = value;
+
+  Vall_ephemerons = result;
+
+  UNGCPRO;
+  return result;
+}
+
+static const struct lrecord_description ephemeron_description[] = {
+  { XD_LISP_OBJECT, offsetof(struct ephemeron, key)},
+  { XD_LISP_OBJECT, offsetof(struct ephemeron, cons_chain)},
+  { XD_LISP_OBJECT, offsetof(struct ephemeron, value)},
+  { XD_END }
+};
+
+DEFINE_LRECORD_IMPLEMENTATION ("ephemeron", ephemeron,
+			       mark_ephemeron, print_ephemeron,
+			       0, ephemeron_equal, ephemeron_hash,
+			       ephemeron_description,
+			       struct ephemeron);
+
+DEFUN ("make-ephemeron", Fmake_ephemeron, 2, 3, 0, /*
+Return a new ephemeron with key KEY, value CONTENTS, and finalizer FINALIZER.
+The ephemeron is a reference to CONTENTS which may be extracted with
+`ephemeron-ref'.  CONTENTS is only reachable through the ephemeron as
+long as KEY is reachable; the ephemeron does not contribute to the
+reachability of KEY.  When KEY becomes unreachable while the ephemeron
+itself is still reachable, CONTENTS is queued for finalization: FINALIZER
+will possibly be called on CONTENTS some time in the future.  Moreover,
+future calls to `ephemeron-ref' will return NIL.
+*/
+       (key, value, finalizer))
+{
+  return make_ephemeron(key, value, finalizer);
+}
+
+DEFUN ("ephemeron-ref",  Fephemeron_ref, 1, 1, 0, /*
+Return the contents of ephemeron EPHEMERON.
+If the contents have been GCed, return NIL.
+*/
+       (eph))
+{
+  return XEPHEMERON_REF (eph);
+}
+
+DEFUN ("ephemeron-p", Fephemeronp, 1, 1, 0, /*
+Return non-nil if OBJECT is an ephemeron.
+*/
+       (object))
+{
+  return EPHEMERONP (object) ? Qt : Qnil;
+}
 
 /************************************************************************/
 /*                            initialization                            */
@@ -2224,6 +2420,7 @@
 syms_of_data (void)
 {
   INIT_LRECORD_IMPLEMENTATION (weak_list);
+  INIT_LRECORD_IMPLEMENTATION (ephemeron);
   INIT_LRECORD_IMPLEMENTATION (weak_box);
 
   DEFSYMBOL (Qquote);
@@ -2342,6 +2539,9 @@
   DEFSUBR (Fweak_list_list);
   DEFSUBR (Fset_weak_list_list);
 
+  DEFSUBR (Fmake_ephemeron);
+  DEFSUBR (Fephemeron_ref);
+  DEFSUBR (Fephemeronp);
   DEFSUBR (Fmake_weak_box);
   DEFSUBR (Fweak_box_ref);
   DEFSUBR (Fweak_boxp);
@@ -2354,6 +2554,12 @@
   Vall_weak_lists = Qnil;
   dump_add_weak_object_chain (&Vall_weak_lists);
 
+  Vall_ephemerons = Qnil;
+  dump_add_weak_object_chain (&Vall_ephemerons);
+
+  Vfinalize_list = Qnil;
+  staticpro (&Vfinalize_list);
+
   Vall_weak_boxes = Qnil;
   dump_add_weak_object_chain (&Vall_weak_boxes);
 
--- a/src/lisp.h	Fri Jun 28 14:21:41 2002 +0000
+++ b/src/lisp.h	Fri Jun 28 14:24:08 2002 +0000
@@ -2571,6 +2571,46 @@
 #define CHECK_WEAK_BOX(x) CHECK_RECORD (x, weak_box)
 #define CONCHECK_WEAK_BOX(x) CONCHECK_RECORD (x, weak_box)
 
+/*--------------------------- ephemerons ----------------------------*/
+
+struct ephemeron 
+{
+  struct lcrecord_header header;
+
+  Lisp_Object key;
+
+  /* This field holds a pair.  The cdr of this cons points to the next
+     ephemeron in Vall_ephemerons.  The car points to another pair
+     whose car is the value and whose cdr is the finalizer.
+
+     This representation makes it very easy to unlink an ephemeron
+     from Vall_ephemerons and chain it into
+     Vall_ephemerons_to_finalize. */
+
+  Lisp_Object cons_chain;
+
+  Lisp_Object value;
+};
+
+void prune_ephemerons (void);
+Lisp_Object ephemeron_value(Lisp_Object ephi);
+int finish_marking_ephemerons(void);
+Lisp_Object zap_finalize_list(void);
+Lisp_Object make_ephemeron(Lisp_Object key, Lisp_Object value, Lisp_Object finalizer);
+
+DECLARE_LRECORD(ephemeron, struct ephemeron);
+#define XEPHEMERON(x) XRECORD (x, ephemeron, struct ephemeron)
+#define XEPHEMERON_REF(x) (XEPHEMERON (x)->value)
+#define XEPHEMERON_NEXT(x) (XCDR (XEPHEMERON(x)->cons_chain))
+#define XEPHEMERON_FINALIZER(x) (XCDR (XCAR (XEPHEMERON (x)->cons_chain)))
+#define XSET_EPHEMERON_NEXT(x, n) (XSETCDR (XEPHEMERON(x)->cons_chain, n))
+#define XSET_EPHEMERON_VALUE(x, v) (XEPHEMERON(x)->value = (v))
+#define XSET_EPHEMERON_KEY(x, k) (XEPHEMERON(x)->key = (k))
+#define wrap_ephemeron(p) wrap_record (p, ephemeron)
+#define EPHEMERONP(x) RECORDP (x, ephemeron)
+#define CHECK_EPHEMERON(x) CHECK_RECORD (x, ephemeron)
+#define CONCHECK_EPHEMERON(x) CONCHECK_RECORD (x, ephemeron)
+
 
 /*---------------------------- weak lists ------------------------------*/
 
@@ -3368,6 +3408,8 @@
 extern int funcall_allocation_flag;
 extern int need_to_garbage_collect;
 extern int need_to_check_c_alloca;
+extern int need_to_signal_post_gc;
+extern Lisp_Object Qpost_gc_hook;
 void recompute_funcall_allocation_flag (void);
 
 #ifdef MEMORY_USAGE_STATS
--- a/src/lrecord.h	Fri Jun 28 14:21:41 2002 +0000
+++ b/src/lrecord.h	Fri Jun 28 14:24:08 2002 +0000
@@ -197,6 +197,7 @@
   lrecord_type_emacs_gtk_object,
   lrecord_type_emacs_gtk_boxed,
   lrecord_type_weak_box,
+  lrecord_type_ephemeron,
   lrecord_type_free, /* only used for "free" lrecords */
   lrecord_type_undefined, /* only used for debugging */
   lrecord_type_last_built_in_type /* must be last */