Add `scm_immutable_double_cell ()'.
authorLudovic Courtès <ludo@gnu.org>
Tue, 16 Sep 2008 10:10:52 +0000 (12:10 +0200)
committerLudovic Courtès <ludo@gnu.org>
Tue, 16 Sep 2008 10:10:52 +0000 (12:10 +0200)
* libguile/inline.h (scm_immutable_double_cell): New.

libguile/inline.h

index 3a4302a..7d2daba 100644 (file)
@@ -83,6 +83,8 @@ SCM_API SCM scm_cell (scm_t_bits car, scm_t_bits cdr);
 SCM_API SCM scm_immutable_cell (scm_t_bits car, scm_t_bits cdr);
 SCM_API SCM scm_double_cell (scm_t_bits car, scm_t_bits cbr,
                             scm_t_bits ccr, scm_t_bits cdr);
+SCM_API SCM scm_immutable_double_cell (scm_t_bits car, scm_t_bits cbr,
+                                      scm_t_bits ccr, scm_t_bits cdr);
 
 SCM_API SCM scm_array_handle_ref (scm_t_array_handle *h, ssize_t pos);
 SCM_API void scm_array_handle_set (scm_t_array_handle *h, ssize_t pos, SCM val);
@@ -188,6 +190,51 @@ scm_double_cell (scm_t_bits car, scm_t_bits cbr,
   return z;
 }
 
+#ifndef SCM_INLINE_C_INCLUDING_INLINE_H
+SCM_C_EXTERN_INLINE
+#endif
+SCM
+scm_immutable_double_cell (scm_t_bits car, scm_t_bits cbr,
+                          scm_t_bits ccr, scm_t_bits cdr)
+{
+  SCM z;
+
+  z = SCM_PACK ((scm_t_bits) (GC_MALLOC_STUBBORN (2 * sizeof (scm_t_cell))));
+  /* Initialize the type slot last so that the cell is ignored by the
+     GC until it is completely initialized.  This is only relevant
+     when the GC can actually run during this code, which it can't
+     since the GC only runs when all other threads are stopped.
+  */
+  SCM_GC_SET_CELL_WORD (z, 1, cbr);
+  SCM_GC_SET_CELL_WORD (z, 2, ccr);
+  SCM_GC_SET_CELL_WORD (z, 3, cdr);
+  SCM_GC_SET_CELL_WORD (z, 0, car);
+
+  GC_END_STUBBORN_CHANGE ((void *) z);
+
+  /* When this function is inlined, it's possible that the last
+     SCM_GC_SET_CELL_WORD above will be adjacent to a following
+     initialization of z.  E.g., it occurred in scm_make_real.  GCC
+     from around version 3 (e.g., certainly 3.2) began taking
+     advantage of strict C aliasing rules which say that it's OK to
+     interchange the initialization above and the one below when the
+     pointer types appear to differ sufficiently.  We don't want that,
+     of course.  GCC allows this behaviour to be disabled with the
+     -fno-strict-aliasing option, but would also need to be supplied
+     by Guile users.  Instead, the following statements prevent the
+     reordering.
+   */
+#ifdef __GNUC__
+  __asm__ volatile ("" : : : "memory");
+#else
+  /* portable version, just in case any other compiler does the same
+     thing.  */
+  scm_remember_upto_here_1 (z);
+#endif
+
+  return z;
+}
+
 #ifndef SCM_INLINE_C_INCLUDING_INLINE_H
 SCM_C_EXTERN_INLINE
 #endif