]> git.donarmstrong.com Git - lilypond.git/blobdiff - guile18/libguile/gc-mark.c
New upstream version 2.19.65
[lilypond.git] / guile18 / libguile / gc-mark.c
diff --git a/guile18/libguile/gc-mark.c b/guile18/libguile/gc-mark.c
new file mode 100644 (file)
index 0000000..3eec72b
--- /dev/null
@@ -0,0 +1,511 @@
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+\f
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef __ia64__
+#include <ucontext.h>
+extern unsigned long * __libc_ia64_register_backing_store_base;
+#endif
+
+#include "libguile/_scm.h"
+#include "libguile/eval.h"
+#include "libguile/stime.h"
+#include "libguile/stackchk.h"
+#include "libguile/struct.h"
+#include "libguile/smob.h"
+#include "libguile/unif.h"
+#include "libguile/async.h"
+#include "libguile/ports.h"
+#include "libguile/root.h"
+#include "libguile/strings.h"
+#include "libguile/vectors.h"
+#include "libguile/weaks.h"
+#include "libguile/hashtab.h"
+#include "libguile/tags.h"
+#include "libguile/private-gc.h"
+#include "libguile/validate.h"
+#include "libguile/deprecation.h"
+#include "libguile/gc.h"
+#include "libguile/guardians.h"
+
+#ifdef GUILE_DEBUG_MALLOC
+#include "libguile/debug-malloc.h"
+#endif
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/*
+  Entry point for this file.
+ */
+void
+scm_mark_all (void)
+{
+  long j;
+  int loops;
+
+  scm_i_init_weak_vectors_for_gc ();
+  scm_i_init_guardians_for_gc ();
+  
+  scm_i_clear_mark_space ();
+  
+  /* Mark every thread's stack and registers */
+  scm_threads_mark_stacks ();
+
+  j = SCM_NUM_PROTECTS;
+  while (j--)
+    scm_gc_mark (scm_sys_protects[j]);
+
+  /* mark the registered roots */
+  {
+    size_t i;
+    for (i = 0; i < SCM_HASHTABLE_N_BUCKETS (scm_gc_registered_roots); ++i)
+      {
+       SCM l = SCM_HASHTABLE_BUCKET (scm_gc_registered_roots, i);
+       for (; !scm_is_null (l); l = SCM_CDR (l))
+         {
+           SCM *p = (SCM *) (scm_to_ulong (SCM_CAAR (l)));
+           scm_gc_mark (*p);
+         }
+      }
+  }
+  
+  scm_mark_subr_table ();
+
+  loops = 0;
+  while (1)
+    {
+      int again;
+      loops++;
+
+      /* Mark the non-weak references of weak vectors.  For a weak key
+        alist vector, this would mark the values for keys that are
+        marked.  We need to do this in a loop until everything
+        settles down since the newly marked values might be keys in
+        other weak key alist vectors, for example.
+      */
+      again = scm_i_mark_weak_vectors_non_weaks ();
+      if (again)
+       continue;
+
+      /* Now we scan all marked guardians and move all unmarked objects
+        from the accessible to the inaccessible list.
+      */
+      scm_i_identify_inaccessible_guardeds ();
+
+      /* When we have identified all inaccessible objects, we can mark
+        them.
+      */
+      again = scm_i_mark_inaccessible_guardeds ();
+
+      /* This marking might have changed the situation for weak vectors
+        and might have turned up new guardians that need to be processed,
+        so we do it all over again.
+      */
+      if (again)
+       continue;
+      
+      /* Nothing new marked in this round, we are done.
+       */
+      break;
+    }
+
+  /* fprintf (stderr, "%d loops\n", loops); */
+
+  /* Remove all unmarked entries from the weak vectors.
+   */
+  scm_i_remove_weaks_from_weak_vectors ();
+  
+  /* Bring hashtables upto date.
+   */
+  scm_i_scan_weak_hashtables ();
+}
+
+/* {Mark/Sweep}
+ */
+
+/*
+  Mark an object precisely, then recurse.
+ */
+void
+scm_gc_mark (SCM ptr)
+{
+  if (SCM_IMP (ptr))
+    return;
+  
+  if (SCM_GC_MARK_P (ptr))
+    return;
+
+  SCM_SET_GC_MARK (ptr);
+  scm_gc_mark_dependencies (ptr);
+}
+
+/*
+
+Mark the dependencies of an object.
+
+Prefetching:
+
+Should prefetch objects before marking, i.e. if marking a cell, we
+should prefetch the car, and then mark the cdr. This will improve CPU
+cache misses, because the car is more likely to be in core when we
+finish the cdr.
+
+See http://www.hpl.hp.com/techreports/2000/HPL-2000-99.pdf, reducing
+garbage collector cache misses.
+
+Prefetch is supported on GCC >= 3.1 
+
+(Some time later.)
+
+Tried this with GCC 3.1.1 -- the time differences are barely measurable.
+Perhaps this would work better with an explicit markstack?
+
+
+*/
+
+void
+scm_gc_mark_dependencies (SCM p)
+#define FUNC_NAME "scm_gc_mark_dependencies"
+{
+  register long i;
+  register SCM ptr;
+  SCM cell_type;
+
+  ptr = p;
+ scm_mark_dependencies_again:
+  
+  cell_type = SCM_GC_CELL_TYPE (ptr);
+  switch (SCM_ITAG7 (cell_type))
+    {
+    case scm_tcs_cons_nimcar:
+      if (SCM_IMP (SCM_CDR (ptr)))
+       {
+         ptr = SCM_CAR (ptr);
+         goto gc_mark_nimp;
+       }
+
+
+      scm_gc_mark (SCM_CAR (ptr));
+      ptr = SCM_CDR (ptr);
+      goto gc_mark_nimp;
+    case scm_tcs_cons_imcar:
+      ptr = SCM_CDR (ptr);
+      goto gc_mark_loop;
+    case scm_tc7_pws:
+
+      scm_gc_mark (SCM_SETTER (ptr));
+      ptr = SCM_PROCEDURE (ptr);
+      goto gc_mark_loop;
+    case scm_tcs_struct:
+      {
+       /* XXX - use less explicit code. */
+       scm_t_bits word0 = SCM_CELL_WORD_0 (ptr) - scm_tc3_struct;
+       scm_t_bits * vtable_data = (scm_t_bits *) word0;
+       SCM layout = SCM_PACK (vtable_data [scm_vtable_index_layout]);
+       long len = scm_i_symbol_length (layout);
+       const char *fields_desc = scm_i_symbol_chars (layout);
+       scm_t_bits *struct_data = (scm_t_bits *) SCM_STRUCT_DATA (ptr);
+
+       if (vtable_data[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
+         {
+           scm_gc_mark (SCM_PACK (struct_data[scm_struct_i_procedure]));
+           scm_gc_mark (SCM_PACK (struct_data[scm_struct_i_setter]));
+         }
+       if (len)
+         {
+           long x;
+
+           for (x = 0; x < len - 2; x += 2, ++struct_data)
+             if (fields_desc[x] == 'p')
+               scm_gc_mark (SCM_PACK (*struct_data));
+           if (fields_desc[x] == 'p')
+             {
+               if (SCM_LAYOUT_TAILP (fields_desc[x + 1]))
+                 for (x = *struct_data++; x; --x, ++struct_data)
+                   scm_gc_mark (SCM_PACK (*struct_data));
+               else
+                 scm_gc_mark (SCM_PACK (*struct_data));
+             }
+         }
+       /* mark vtable */
+       ptr = SCM_PACK (vtable_data [scm_vtable_index_vtable]);
+       goto gc_mark_loop;
+      }
+      break;
+    case scm_tcs_closures:
+      if (SCM_IMP (SCM_ENV (ptr)))
+       {
+         ptr = SCM_CLOSCAR (ptr);
+         goto gc_mark_nimp;
+       }
+      scm_gc_mark (SCM_CLOSCAR (ptr));
+      ptr = SCM_ENV (ptr);
+      goto gc_mark_nimp;
+    case scm_tc7_vector:
+      i = SCM_SIMPLE_VECTOR_LENGTH (ptr);
+      if (i == 0)
+       break;
+      while (--i > 0)
+       {
+         SCM elt = SCM_SIMPLE_VECTOR_REF (ptr, i);
+         if (SCM_NIMP (elt))
+           scm_gc_mark (elt);
+       }
+      ptr = SCM_SIMPLE_VECTOR_REF (ptr, 0);
+      goto gc_mark_loop;
+#ifdef CCLO
+    case scm_tc7_cclo:
+      {
+       size_t i = SCM_CCLO_LENGTH (ptr);
+       size_t j;
+       for (j = 1; j != i; ++j)
+         {
+           SCM obj = SCM_CCLO_REF (ptr, j);
+           if (!SCM_IMP (obj))
+             scm_gc_mark (obj);
+         }
+       ptr = SCM_CCLO_REF (ptr, 0);
+       goto gc_mark_loop;
+      }
+#endif
+
+    case scm_tc7_string:
+      ptr = scm_i_string_mark (ptr);
+      goto gc_mark_loop;
+    case scm_tc7_stringbuf:
+      ptr = scm_i_stringbuf_mark (ptr);
+      goto gc_mark_loop;
+
+    case scm_tc7_number:
+      if (SCM_TYP16 (ptr) == scm_tc16_fraction)
+       {
+         scm_gc_mark (SCM_CELL_OBJECT_1 (ptr));
+         ptr = SCM_CELL_OBJECT_2 (ptr);
+         goto gc_mark_loop;
+       }
+      break;
+
+    case scm_tc7_wvect:
+      scm_i_mark_weak_vector (ptr);
+      break;
+
+    case scm_tc7_symbol:
+      ptr = scm_i_symbol_mark (ptr);
+      goto gc_mark_loop;
+    case scm_tc7_variable:
+      ptr = SCM_CELL_OBJECT_1 (ptr);
+      goto gc_mark_loop;
+    case scm_tcs_subrs:
+      break;
+    case scm_tc7_port:
+      i = SCM_PTOBNUM (ptr);
+#if (SCM_DEBUG_CELL_ACCESSES == 1) 
+      if (!(i < scm_numptob))
+       {
+         fprintf (stderr, "undefined port type");
+         abort();
+       }
+#endif
+      if (SCM_PTAB_ENTRY(ptr))
+       scm_gc_mark (SCM_FILENAME (ptr));
+      if (scm_ptobs[i].mark)
+       {
+         ptr = (scm_ptobs[i].mark) (ptr);
+         goto gc_mark_loop;
+       }
+      else
+       return;
+      break;
+    case scm_tc7_smob:
+      switch (SCM_TYP16 (ptr))
+       { /* should be faster than going through scm_smobs */
+       case scm_tc_free_cell:
+         /* We have detected a free cell.  This can happen if non-object data
+          * on the C stack points into guile's heap and is scanned during
+          * conservative marking.  */
+         break;
+       default:
+         i = SCM_SMOBNUM (ptr);
+#if (SCM_DEBUG_CELL_ACCESSES == 1)
+         if (!(i < scm_numsmob))
+           {
+             fprintf (stderr, "undefined smob type");
+             abort();
+           }
+#endif
+         if (scm_smobs[i].mark)
+           {
+             ptr = (scm_smobs[i].mark) (ptr);
+             goto gc_mark_loop;
+           }
+         else
+           return;
+       }
+      break;
+    default:
+      fprintf (stderr, "unknown type");
+      abort();
+    }
+
+  /*
+    If we got here, then exhausted recursion options for PTR.  we
+    return (careful not to mark PTR, it might be the argument that we
+    were called with.)
+   */
+  return ;
+
+ gc_mark_loop:
+  if (SCM_IMP (ptr))
+    return;
+
+ gc_mark_nimp:
+  {
+    int valid_cell = CELL_P (ptr);
+
+    
+#if (SCM_DEBUG_CELL_ACCESSES == 1)
+    if (scm_debug_cell_accesses_p)
+      {
+    /* We are in debug mode.  Check the ptr exhaustively. */
+       
+       valid_cell = valid_cell && (scm_i_find_heap_segment_containing_object (ptr) >= 0);
+      }
+    
+#endif
+    if (!valid_cell)
+      {
+       fprintf (stderr, "rogue pointer in heap");
+       abort();
+      }
+  }
+  
+ if (SCM_GC_MARK_P (ptr))
+  {
+    return;
+  }
+  
+  SCM_SET_GC_MARK (ptr);
+
+  goto   scm_mark_dependencies_again;
+  
+}
+#undef FUNC_NAME
+
+
+
+
+/* Mark a region conservatively */
+void
+scm_mark_locations (SCM_STACKITEM x[], unsigned long n)
+{
+  unsigned long m;
+
+  for (m = 0; m < n; ++m)
+    {
+      SCM obj = * (SCM *) &x[m];
+      long int segment = scm_i_find_heap_segment_containing_object (obj);
+      if (segment >= 0)
+       scm_gc_mark (obj);
+    }
+}
+
+
+/* The function scm_in_heap_p determines whether an SCM value can be regarded as a
+ * pointer to a cell on the heap.
+ */
+int
+scm_in_heap_p (SCM value)
+{
+  long int segment = scm_i_find_heap_segment_containing_object (value);
+  return (segment >= 0);
+}
+
+
+#if SCM_ENABLE_DEPRECATED == 1
+
+/* If an allocated cell is detected during garbage collection, this
+ * means that some code has just obtained the object but was preempted
+ * before the initialization of the object was completed.  This meanst
+ * that some entries of the allocated cell may already contain SCM
+ * objects.  Therefore, allocated cells are scanned conservatively.
+ */
+
+scm_t_bits scm_tc16_allocated;
+
+static SCM
+allocated_mark (SCM cell)
+{
+  unsigned long int cell_segment = scm_i_find_heap_segment_containing_object (cell);
+  unsigned int span = scm_i_heap_segment_table[cell_segment]->span;
+  unsigned int i;
+
+  for (i = 1; i != span * 2; ++i)
+    {
+      SCM obj = SCM_CELL_OBJECT (cell, i);
+      long int obj_segment = scm_i_find_heap_segment_containing_object (obj);
+      if (obj_segment >= 0)
+       scm_gc_mark (obj);
+    }
+  return SCM_BOOL_F;
+}
+
+SCM
+scm_deprecated_newcell (void)
+{
+  scm_c_issue_deprecation_warning 
+    ("SCM_NEWCELL is deprecated.  Use `scm_cell' instead.\n");
+
+  return scm_cell (scm_tc16_allocated, 0);
+}
+
+SCM
+scm_deprecated_newcell2 (void)
+{
+  scm_c_issue_deprecation_warning 
+    ("SCM_NEWCELL2 is deprecated.  Use `scm_double_cell' instead.\n");
+
+  return scm_double_cell (scm_tc16_allocated, 0, 0, 0);
+}
+
+#endif /* SCM_ENABLE_DEPRECATED == 1 */
+
+
+void
+scm_gc_init_mark(void)
+{
+#if SCM_ENABLE_DEPRECATED == 1
+  scm_tc16_allocated = scm_make_smob_type ("allocated cell", 0);
+  scm_set_smob_mark (scm_tc16_allocated, allocated_mark);
+#endif
+}
+