Finish stable split
authorDavid Feuer <david.feuer@gmail.com>
Wed, 29 Aug 2018 20:34:21 +0000 (16:34 -0400)
committerDavid Feuer <David.Feuer@gmail.com>
Wed, 29 Aug 2018 20:34:22 +0000 (16:34 -0400)
Long ago, the stable name table and stable pointer tables were one.
Now, they are separate, and have significantly different
implementations. I believe the time has come to finish the split
that began in #7674.

* Divide `rts/Stable` into `rts/StableName` and `rts/StablePtr`.

* Give each table its own mutex.

* Add FFI functions `hs_lock_stable_ptr_table` and
`hs_unlock_stable_ptr_table` and document them.
  These are intended to replace the previously undocumented
`hs_lock_stable_tables` and `hs_lock_stable_tables`,
  which are now documented as deprecated synonyms.

* Make `eqStableName#` use pointer equality instead of unnecessarily
comparing stable name table indices.

Reviewers: simonmar, bgamari, erikd

Reviewed By: bgamari

Subscribers: rwbarton, carter

GHC Trac Issues: #15555

Differential Revision: https://phabricator.haskell.org/D5084

30 files changed:
compiler/codeGen/StgCmmPrim.hs
docs/users_guide/8.8.1-notes.rst
docs/users_guide/ffi-chap.rst
includes/HsFFI.h
includes/Rts.h
includes/rts/StableName.h [moved from includes/rts/Stable.h with 69% similarity]
includes/rts/StablePtr.h [new file with mode: 0644]
includes/stg/MiscClosures.h
rts/Adjustor.c
rts/Globals.c
rts/HsFFI.c
rts/Interpreter.c
rts/Linker.c
rts/RetainerProfile.c
rts/RtsAPI.c
rts/RtsStartup.c
rts/RtsSymbols.c
rts/Schedule.c
rts/StableName.c [moved from rts/Stable.c with 55% similarity]
rts/StableName.h [new file with mode: 0644]
rts/StablePtr.c [new file with mode: 0644]
rts/StablePtr.h [moved from rts/Stable.h with 54% similarity]
rts/StaticPtrTable.c
rts/TopHandler.c
rts/TopHandler.h
rts/posix/Signals.c
rts/rts.cabal.in
rts/sm/Compact.c
rts/sm/GC.c
utils/deriveConstants/Main.hs

index a6e1308..266ab3a 100644 (file)
@@ -352,14 +352,6 @@ emitPrimOp dflags [res] ByteArrayContents_Char [arg]
 emitPrimOp dflags [res] StableNameToIntOp [arg]
    = emitAssign (CmmLocal res) (cmmLoadIndexW dflags arg (fixedHdrSizeW dflags) (bWord dflags))
 
---  #define eqStableNamezh(r,sn1,sn2)                                   \
---    (r = (((StgStableName *)sn1)->sn == ((StgStableName *)sn2)->sn))
-emitPrimOp dflags [res] EqStableNameOp [arg1,arg2]
-   = emitAssign (CmmLocal res) (CmmMachOp (mo_wordEq dflags) [
-                                   cmmLoadIndexW dflags arg1 (fixedHdrSizeW dflags) (bWord dflags),
-                                   cmmLoadIndexW dflags arg2 (fixedHdrSizeW dflags) (bWord dflags)
-                         ])
-
 emitPrimOp dflags [res] ReallyUnsafePtrEqualityOp [arg1,arg2]
    = emitAssign (CmmLocal res) (CmmMachOp (mo_wordEq dflags) [arg1,arg2])
 
@@ -1405,9 +1397,22 @@ translateOp dflags SameMutableArrayArrayOp= Just (mo_wordEq dflags)
 translateOp dflags SameSmallMutableArrayOp= Just (mo_wordEq dflags)
 translateOp dflags SameTVarOp             = Just (mo_wordEq dflags)
 translateOp dflags EqStablePtrOp          = Just (mo_wordEq dflags)
+-- See Note [Comparing stable names]
+translateOp dflags EqStableNameOp         = Just (mo_wordEq dflags)
 
 translateOp _      _ = Nothing
 
+-- Note [Comparing stable names]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--
+-- A StableName# is actually a pointer to a stable name object (SNO)
+-- containing an index into the stable name table (SNT). We
+-- used to compare StableName#s by following the pointers to the
+-- SNOs and checking whether they held the same SNT indices. However,
+-- this is not necessary: there is a one-to-one correspondence
+-- between SNOs and entries in the SNT, so simple pointer equality
+-- does the trick.
+
 -- These primops are implemented by CallishMachOps, because they sometimes
 -- turn into foreign calls depending on the backend.
 
index da236f9..50323b3 100644 (file)
@@ -48,6 +48,14 @@ Compiler
 Runtime system
 ~~~~~~~~~~~~~~
 
+- Add and document new FFI functions ``hs_lock_stable_ptr_table``
+  and ``hs_unlock_stable_ptr_table``. These replace the undocumented
+  functions ``hs_lock_stable_tables`` and ``hs_unlock_stable_tables``,
+  respectively. The latter should now be considered deprecated.
+
+- Document the heretofore undocumented FFI function
+  ``hs_free_stable_ptr_unsafe``, used in conjunction with manual
+  locking and unlocking.
 
 Template Haskell
 ~~~~~~~~~~~~~~~~
index 0b107de..62bad46 100644 (file)
@@ -245,6 +245,46 @@ allocated until ``hs_exit()`` is called. If you call it too often, the
 worst that can happen is that the next call to a Haskell function incurs
 some extra overhead.
 
+.. _ffi-stable-ptr-extras:
+
+Freeing many stable pointers efficiently
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The standard function ``hs_free_stable_ptr`` locks the stable pointer
+table, frees the given stable pointer, and then unlocks the stable pointer
+table again. When freeing many stable pointers at once, it is usually
+more efficient to lock and unlock the table only once.
+
+.. code-block:: c
+
+    extern void hs_lock_stable_ptr_table (void);
+
+    extern void hs_unlock_stable_ptr_table (void);
+
+    extern void hs_free_stable_ptr_unsafe (HsStablePtr sp);
+
+``hs_free_stable_ptr_unsafe`` must be used *only* when the table has been
+locked using ``hs_lock_stable_ptr_table``. It must be unlocked afterwards
+using ``hs_unlock_stable_ptr_table``. The Haskell garbage collector cannot
+run while the table is locked, so it should be unlocked promptly. The
+following operations are forbidden while the stable pointer table is locked:
+
+* Calling any Haskell function, whether or not that function
+  manipulates stable pointers.
+
+* Calling any FFI function that deals with the stable pointer table
+  except for arbitrarily many calls to ``hs_free_stable_ptr_unsafe``
+  and the final call to ``hs_unlock_stable_ptr_table``.
+
+* Calling ``hs_free_fun_ptr``.
+
+.. note::
+
+    GHC versions before 8.8 defined undocumented functions
+    ``hs_lock_stable_tables`` and ``hs_unlock_stable_tables`` instead
+    of ``hs_lock_stable_ptr_table`` and ``hs_unlock_stable_ptr_table``.
+    Those names are now deprecated.
+
 .. _ffi-ghc:
 
 Using the FFI with GHC
index dea365c..8497647 100644 (file)
@@ -101,8 +101,26 @@ extern void hs_thread_done (void);
 
 extern void hs_perform_gc (void);
 
+// Lock the stable pointer table. The table must be unlocked
+// again before calling any Haskell functions, even if those
+// functions do not manipulate stable pointers. The Haskell
+// garbage collector will not be able to run until this lock
+// is released! It is also forbidden to call hs_free_fun_ptr
+// or any stable pointer-related FFI functions other than
+// hs_free_stable_ptr_unsafe while the table is locked.
+extern void hs_lock_stable_ptr_table (void);
+
+// A deprecated synonym.
 extern void hs_lock_stable_tables (void);
+
+// Unlock the stable pointer table.
+extern void hs_unlock_stable_ptr_table (void);
+
+// A deprecated synonym.
 extern void hs_unlock_stable_tables (void);
+
+// Free a stable pointer assuming that the stable pointer
+// table is already locked.
 extern void hs_free_stable_ptr_unsafe (HsStablePtr sp);
 
 extern void hs_free_stable_ptr (HsStablePtr sp);
index fc70479..eb11536 100644 (file)
@@ -198,7 +198,8 @@ void _assertFail(const char *filename, unsigned int linenum)
 #include "rts/Linker.h"
 #include "rts/Ticky.h"
 #include "rts/Timer.h"
-#include "rts/Stable.h"
+#include "rts/StablePtr.h"
+#include "rts/StableName.h"
 #include "rts/TTY.h"
 #include "rts/Utils.h"
 #include "rts/PrimFloat.h"
similarity index 69%
rename from includes/rts/Stable.h
rename to includes/rts/StableName.h
index 4550ad6..d43ffcb 100644 (file)
@@ -2,7 +2,7 @@
  *
  * (c) The GHC Team, 1998-2009
  *
- * Stable Pointers
+ * Stable Names
  *
  * Do not #include this file directly: #include "Rts.h" instead.
  *
@@ -13,9 +13,6 @@
 
 #pragma once
 
-EXTERN_INLINE StgPtr deRefStablePtr (StgStablePtr stable_ptr);
-StgStablePtr getStablePtr  (StgPtr p);
-
 /* -----------------------------------------------------------------------------
    PRIVATE from here.
    -------------------------------------------------------------------------- */
@@ -32,17 +29,4 @@ typedef struct {
                          // free
 } snEntry;
 
-typedef struct {
-    StgPtr addr;         // Haskell object when entry is in use, next free
-                         // entry (NULL when this is the last free entry)
-                         // otherwise.
-} spEntry;
-
 extern DLL_IMPORT_RTS snEntry *stable_name_table;
-extern DLL_IMPORT_RTS spEntry *stable_ptr_table;
-
-EXTERN_INLINE
-StgPtr deRefStablePtr(StgStablePtr sp)
-{
-    return stable_ptr_table[(StgWord)sp].addr;
-}
diff --git a/includes/rts/StablePtr.h b/includes/rts/StablePtr.h
new file mode 100644 (file)
index 0000000..0d3642f
--- /dev/null
@@ -0,0 +1,35 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2009
+ *
+ * Stable Pointers
+ *
+ * Do not #include this file directly: #include "Rts.h" instead.
+ *
+ * To understand the structure of the RTS headers, see the wiki:
+ *   http://ghc.haskell.org/trac/ghc/wiki/Commentary/SourceTree/Includes
+ *
+ * ---------------------------------------------------------------------------*/
+
+#pragma once
+
+EXTERN_INLINE StgPtr deRefStablePtr (StgStablePtr stable_ptr);
+StgStablePtr getStablePtr  (StgPtr p);
+
+/* -----------------------------------------------------------------------------
+   PRIVATE from here.
+   -------------------------------------------------------------------------- */
+
+typedef struct {
+    StgPtr addr;         // Haskell object when entry is in use, next free
+                         // entry (NULL when this is the last free entry)
+                         // otherwise.
+} spEntry;
+
+extern DLL_IMPORT_RTS spEntry *stable_ptr_table;
+
+EXTERN_INLINE
+StgPtr deRefStablePtr(StgStablePtr sp)
+{
+    return stable_ptr_table[(StgWord)sp].addr;
+}
index 5328ed3..c13b5ff 100644 (file)
@@ -514,8 +514,10 @@ extern StgWord RTS_VAR(atomic_modify_mutvar_mutex);
 // RtsFlags
 extern StgWord RTS_VAR(RtsFlags); // bogus type
 
-// Stable.c
+// StablePtr.c
 extern StgWord RTS_VAR(stable_ptr_table);
+
+// StableName.c
 extern StgWord RTS_VAR(stable_name_table);
 
 // Profiling.c
index a1bfeb9..476d631 100644 (file)
@@ -40,7 +40,7 @@ Haskell side.
 #include "Rts.h"
 
 #include "RtsUtils.h"
-#include "Stable.h"
+#include "StablePtr.h"
 
 #if defined(USE_LIBFFI_FOR_ADJUSTORS)
 #include "ffi.h"
index 66c17d0..c9980d9 100644 (file)
@@ -21,7 +21,7 @@
 #include "Rts.h"
 
 #include "Globals.h"
-#include "Stable.h"
+#include "StablePtr.h"
 
 typedef enum {
     GHCConcSignalSignalHandlerStore,
index 8fae246..e482932 100644 (file)
@@ -10,7 +10,7 @@
 #include "HsFFI.h"
 #include "Rts.h"
 
-#include "Stable.h"
+#include "StablePtr.h"
 #include "Task.h"
 
 // hs_init and hs_exit are defined in RtsStartup.c
@@ -28,14 +28,28 @@ hs_perform_gc(void)
     performMajorGC();
 }
 
+// Lock the stable pointer table
+void hs_lock_stable_ptr_table (void)
+{
+    stablePtrLock();
+}
+
+// Deprecated version of hs_lock_stable_ptr_table
 void hs_lock_stable_tables (void)
 {
-    stableLock();
+    stablePtrLock();
+}
+
+// Unlock the stable pointer table
+void hs_unlock_stable_ptr_table (void)
+{
+    stablePtrUnlock();
 }
 
+// Deprecated version of hs_unlock_stable_ptr_table
 void hs_unlock_stable_tables (void)
 {
-    stableUnlock();
+    stablePtrUnlock();
 }
 
 void
index 9eb6560..a3b179a 100644 (file)
@@ -16,7 +16,7 @@
 #include "Schedule.h"
 #include "Updates.h"
 #include "Prelude.h"
-#include "Stable.h"
+#include "StablePtr.h"
 #include "Printer.h"
 #include "Profiling.h"
 #include "Disassembler.h"
index aa6ec7f..934b907 100644 (file)
@@ -22,7 +22,7 @@
 #include "StgPrimFloat.h" // for __int_encodeFloat etc.
 #include "Proftimer.h"
 #include "GetEnv.h"
-#include "Stable.h"
+#include "StablePtr.h"
 #include "RtsSymbols.h"
 #include "RtsSymbolInfo.h"
 #include "Profiling.h"
index 8a64de9..d67eeb4 100644 (file)
@@ -30,7 +30,8 @@
 #include "Stats.h"
 #include "ProfHeap.h"
 #include "Apply.h"
-#include "Stable.h" /* markStableTables */
+#include "StablePtr.h" /* markStablePtrTable */
+#include "StableName.h" /* rememberOldStableNameAddresses */
 #include "sm/Storage.h" // for END_OF_STATIC_LIST
 
 /* Note [What is a retainer?]
@@ -1693,7 +1694,9 @@ computeRetainerSet( void )
     }
 
     // Consider roots from the stable ptr table.
-    markStableTables(retainRoot, NULL);
+    markStablePtrTable(retainRoot, NULL);
+    // Remember old stable name addresses.
+    rememberOldStableNameAddresses ();
 
     // The following code resets the rs field of each unvisited mutable
     // object (computing sumOfNewCostExtra and updating costArray[] when
index 8fd1917..9396dcc 100644 (file)
@@ -15,7 +15,7 @@
 #include "Prelude.h"
 #include "Schedule.h"
 #include "Capability.h"
-#include "Stable.h"
+#include "StablePtr.h"
 #include "Threads.h"
 #include "Weak.h"
 
index 0cb1ff9..5e5aef3 100644 (file)
@@ -26,7 +26,8 @@
 #include "ThreadLabels.h"
 #include "sm/BlockAlloc.h"
 #include "Trace.h"
-#include "Stable.h"
+#include "StableName.h"
+#include "StablePtr.h"
 #include "StaticPtrTable.h"
 #include "Hash.h"
 #include "Profiling.h"
@@ -243,7 +244,10 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
     initStorage();
 
     /* initialise the stable pointer table */
-    initStableTables();
+    initStablePtrTable();
+
+    /* initialise the stable name table */
+    initStableNameTable();
 
     /* Add some GC roots for things in the base package that the RTS
      * knows about.  We don't know whether these turn out to be CAFs
@@ -451,7 +455,10 @@ hs_exit_(bool wait_foreign)
     exitTopHandler();
 
     /* free the stable pointer table */
-    exitStableTables();
+    exitStablePtrTable();
+
+    /* free the stable name table */
+    exitStableNameTable();
 
 #if defined(DEBUG)
     /* free the thread label table */
index 79ab3f1..5091c90 100644 (file)
       SymI_HasProto(hs_exit_nowait)                                     \
       SymI_HasProto(hs_set_argv)                                        \
       SymI_HasProto(hs_perform_gc)                                      \
+      SymI_HasProto(hs_lock_stable_ptr_table)                           \
+      SymI_HasProto(hs_unlock_stable_ptr_table)                         \
       SymI_HasProto(hs_lock_stable_tables)                              \
       SymI_HasProto(hs_unlock_stable_tables)                            \
       SymI_HasProto(hs_free_stable_ptr)                                 \
index cf975b5..0444f0c 100644 (file)
@@ -41,7 +41,8 @@
 #include "Timer.h"
 #include "ThreadPaused.h"
 #include "Messages.h"
-#include "Stable.h"
+#include "StablePtr.h"
+#include "StableName.h"
 #include "TopHandler.h"
 
 #if defined(HAVE_SYS_TYPES_H)
@@ -1964,7 +1965,8 @@ forkProcess(HsStablePtr *entry
     // inconsistent state in the child.  See also #1391.
     ACQUIRE_LOCK(&sched_mutex);
     ACQUIRE_LOCK(&sm_mutex);
-    ACQUIRE_LOCK(&stable_mutex);
+    ACQUIRE_LOCK(&stable_ptr_mutex);
+    ACQUIRE_LOCK(&stable_name_mutex);
     ACQUIRE_LOCK(&task->lock);
 
     for (i=0; i < n_capabilities; i++) {
@@ -1989,7 +1991,8 @@ forkProcess(HsStablePtr *entry
 
         RELEASE_LOCK(&sched_mutex);
         RELEASE_LOCK(&sm_mutex);
-        RELEASE_LOCK(&stable_mutex);
+        RELEASE_LOCK(&stable_ptr_mutex);
+        RELEASE_LOCK(&stable_name_mutex);
         RELEASE_LOCK(&task->lock);
 
 #if defined(THREADED_RTS)
@@ -2012,7 +2015,8 @@ forkProcess(HsStablePtr *entry
 #if defined(THREADED_RTS)
         initMutex(&sched_mutex);
         initMutex(&sm_mutex);
-        initMutex(&stable_mutex);
+        initMutex(&stable_ptr_mutex);
+        initMutex(&stable_name_mutex);
         initMutex(&task->lock);
 
         for (i=0; i < n_capabilities; i++) {
similarity index 55%
rename from rts/Stable.c
rename to rts/StableName.c
index 71eaf1a..abe7b69 100644 (file)
@@ -4,7 +4,7 @@
  *
  * (c) The GHC Team, 1998-2002
  *
- * Stable names and stable pointers.
+ * Stable names
  *
  * ---------------------------------------------------------------------------*/
 
 #include "Hash.h"
 #include "RtsUtils.h"
 #include "Trace.h"
-#include "Stable.h"
+#include "StableName.h"
 
 #include <string.h>
 
-/* Comment from ADR's implementation in old RTS:
-
-  This files (together with @ghc/runtime/storage/PerformIO.lhc@ and a
-  small change in @HpOverflow.lc@) consists of the changes in the
-  runtime system required to implement "Stable Pointers". But we're
-  getting a bit ahead of ourselves --- what is a stable pointer and what
-  is it used for?
-
-  When Haskell calls C, it normally just passes over primitive integers,
-  floats, bools, strings, etc.  This doesn't cause any problems at all
-  for garbage collection because the act of passing them makes a copy
-  from the heap, stack or wherever they are onto the C-world stack.
-  However, if we were to pass a heap object such as a (Haskell) @String@
-  and a garbage collection occured before we finished using it, we'd run
-  into problems since the heap object might have been moved or even
-  deleted.
-
-  So, if a C call is able to cause a garbage collection or we want to
-  store a pointer to a heap object between C calls, we must be careful
-  when passing heap objects. Our solution is to keep a table of all
-  objects we've given to the C-world and to make sure that the garbage
-  collector collects these objects --- updating the table as required to
-  make sure we can still find the object.
-
-
-  Of course, all this rather begs the question: why would we want to
-  pass a boxed value?
-
-  One very good reason is to preserve laziness across the language
-  interface. Rather than evaluating an integer or a string because it
-  {\em might\/} be required by the C function, we can wait until the C
-  function actually wants the value and then force an evaluation.
-
-  Another very good reason (the motivating reason!) is that the C code
-  might want to execute an object of sort $IO ()$ for the side-effects
-  it will produce. For example, this is used when interfacing to an X
-  widgets library to allow a direct implementation of callbacks.
-
-  One final reason is that we may want to store composite Haskell
-  values in data structures implemented in the C side. Serializing and
-  deserializing these structures into unboxed form suitable for C may
-  be more expensive than maintaining the extra layer of indirection of
-  stable pointers.
-
-  The @makeStablePointer :: a -> IO (StablePtr a)@ function
-  converts a value into a stable pointer.  It is part of the @PrimIO@
-  monad, because we want to be sure we don't allocate one twice by
-  accident, and then only free one of the copies.
-
-  \begin{verbatim}
-  makeStablePtr#  :: a -> State# RealWorld -> (# RealWorld, a #)
-  freeStablePtr#  :: StablePtr# a -> State# RealWorld -> State# RealWorld
-  deRefStablePtr# :: StablePtr# a -> State# RealWorld ->
-        (# State# RealWorld, a #)
-  \end{verbatim}
-
-  There may be additional functions on the C side to allow evaluation,
-  application, etc of a stable pointer.
-
-  Stable Pointers are exported to the outside world as indices and not
-  pointers, because the stable pointer table is allowed to be
-  reallocated for growth. The table is never shrunk for its space to
-  be reclaimed.
-
-  Future plans for stable ptrs include distinguishing them by the
-  generation of the pointed object. See
-  http://ghc.haskell.org/trac/ghc/ticket/7670 for details.
-*/
-
 snEntry *stable_name_table = NULL;
 static snEntry *stable_name_free = NULL;
 static unsigned int SNT_size = 0;
 #define INIT_SNT_SIZE 64
 
-spEntry *stable_ptr_table = NULL;
-static spEntry *stable_ptr_free = NULL;
-static unsigned int SPT_size = 0;
-#define INIT_SPT_SIZE 64
-
-/* Each time the stable pointer table is enlarged, we temporarily retain the old
- * version to ensure dereferences are thread-safe (see Note [Enlarging the
- * stable pointer table]).  Since we double the size of the table each time, we
- * can (theoretically) enlarge it at most N times on an N-bit machine.  Thus,
- * there will never be more than N old versions of the table.
- */
-#if SIZEOF_VOID_P == 4
-#define MAX_N_OLD_SPTS 32
-#elif SIZEOF_VOID_P == 8
-#define MAX_N_OLD_SPTS 64
-#else
-#error unknown SIZEOF_VOID_P
-#endif
-
-static spEntry *old_SPTs[MAX_N_OLD_SPTS];
-static uint32_t n_old_SPTs = 0;
-
 #if defined(THREADED_RTS)
-Mutex stable_mutex;
+Mutex stable_name_mutex;
 #endif
 
 static void enlargeStableNameTable(void);
-static void enlargeStablePtrTable(void);
 
 /*
  * This hash table maps Haskell objects to stable names, so that every
@@ -130,26 +38,21 @@ static void enlargeStablePtrTable(void);
 
 static HashTable *addrToStableHash = NULL;
 
-/* -----------------------------------------------------------------------------
- * We must lock the StablePtr table during GC, to prevent simultaneous
- * calls to freeStablePtr().
- * -------------------------------------------------------------------------- */
-
 void
-stableLock(void)
+stableNameLock(void)
 {
-    initStableTables();
-    ACQUIRE_LOCK(&stable_mutex);
+    initStableNameTable();
+    ACQUIRE_LOCK(&stable_name_mutex);
 }
 
 void
-stableUnlock(void)
+stableNameUnlock(void)
 {
-    RELEASE_LOCK(&stable_mutex);
+    RELEASE_LOCK(&stable_name_mutex);
 }
 
 /* -----------------------------------------------------------------------------
- * Initialising the tables
+ * Initialising the table
  * -------------------------------------------------------------------------- */
 
 STATIC_INLINE void
@@ -165,19 +68,8 @@ initSnEntryFreeList(snEntry *table, uint32_t n, snEntry *free)
   stable_name_free = table;
 }
 
-STATIC_INLINE void
-initSpEntryFreeList(spEntry *table, uint32_t n, spEntry *free)
-{
-  spEntry *p;
-  for (p = table + n - 1; p >= table; p--) {
-      p->addr = (P_)free;
-      free = p;
-  }
-  stable_ptr_free = table;
-}
-
 void
-initStableTables(void)
+initStableNameTable(void)
 {
     if (SNT_size > 0) return;
     SNT_size = INIT_SNT_SIZE;
@@ -190,14 +82,8 @@ initStableTables(void)
     initSnEntryFreeList(stable_name_table + 1,INIT_SNT_SIZE-1,NULL);
     addrToStableHash = allocHashTable();
 
-    if (SPT_size > 0) return;
-    SPT_size = INIT_SPT_SIZE;
-    stable_ptr_table = stgMallocBytes(SPT_size * sizeof(spEntry),
-                                      "initStablePtrTable");
-    initSpEntryFreeList(stable_ptr_table,INIT_SPT_SIZE,NULL);
-
 #if defined(THREADED_RTS)
-    initMutex(&stable_mutex);
+    initMutex(&stable_name_mutex);
 #endif
 }
 
@@ -220,37 +106,6 @@ enlargeStableNameTable(void)
     initSnEntryFreeList(stable_name_table + old_SNT_size, old_SNT_size, NULL);
 }
 
-// Must be holding stable_mutex
-static void
-enlargeStablePtrTable(void)
-{
-    uint32_t old_SPT_size = SPT_size;
-    spEntry *new_stable_ptr_table;
-
-    // 2nd and subsequent times
-    SPT_size *= 2;
-
-    /* We temporarily retain the old version instead of freeing it; see Note
-     * [Enlarging the stable pointer table].
-     */
-    new_stable_ptr_table =
-        stgMallocBytes(SPT_size * sizeof(spEntry),
-                       "enlargeStablePtrTable");
-    memcpy(new_stable_ptr_table,
-           stable_ptr_table,
-           old_SPT_size * sizeof(spEntry));
-    ASSERT(n_old_SPTs < MAX_N_OLD_SPTS);
-    old_SPTs[n_old_SPTs++] = stable_ptr_table;
-
-    /* When using the threaded RTS, the update of stable_ptr_table is assumed to
-     * be atomic, so that another thread simultaneously dereferencing a stable
-     * pointer will always read a valid address.
-     */
-    stable_ptr_table = new_stable_ptr_table;
-
-    initSpEntryFreeList(stable_ptr_table + old_SPT_size, old_SPT_size, NULL);
-}
-
 /* Note [Enlarging the stable pointer table]
  *
  * To enlarge the stable pointer table, we allocate a new table, copy the
@@ -271,19 +126,8 @@ enlargeStablePtrTable(void)
  * Freeing entries and tables
  * -------------------------------------------------------------------------- */
 
-static void
-freeOldSPTs(void)
-{
-    uint32_t i;
-
-    for (i = 0; i < n_old_SPTs; i++) {
-        stgFree(old_SPTs[i]);
-    }
-    n_old_SPTs = 0;
-}
-
 void
-exitStableTables(void)
+exitStableNameTable(void)
 {
     if (addrToStableHash)
         freeHashTable(addrToStableHash, NULL);
@@ -294,15 +138,8 @@ exitStableTables(void)
     stable_name_table = NULL;
     SNT_size = 0;
 
-    if (stable_ptr_table)
-        stgFree(stable_ptr_table);
-    stable_ptr_table = NULL;
-    SPT_size = 0;
-
-    freeOldSPTs();
-
 #if defined(THREADED_RTS)
-    closeMutex(&stable_mutex);
+    closeMutex(&stable_name_mutex);
 #endif
 }
 
@@ -315,28 +152,6 @@ freeSnEntry(snEntry *sn)
   stable_name_free = sn;
 }
 
-STATIC_INLINE void
-freeSpEntry(spEntry *sp)
-{
-    sp->addr = (P_)stable_ptr_free;
-    stable_ptr_free = sp;
-}
-
-void
-freeStablePtrUnsafe(StgStablePtr sp)
-{
-    ASSERT((StgWord)sp < SPT_size);
-    freeSpEntry(&stable_ptr_table[(StgWord)sp]);
-}
-
-void
-freeStablePtr(StgStablePtr sp)
-{
-    stableLock();
-    freeStablePtrUnsafe(sp);
-    stableUnlock();
-}
-
 /* -----------------------------------------------------------------------------
  * Looking up
  * -------------------------------------------------------------------------- */
@@ -377,7 +192,7 @@ removeIndirections (StgClosure* p)
 StgWord
 lookupStableName (StgPtr p)
 {
-  stableLock();
+  stableNameLock();
 
   if (stable_name_free == NULL) {
     enlargeStableNameTable();
@@ -396,7 +211,7 @@ lookupStableName (StgPtr p)
   if (sn != 0) {
     ASSERT(stable_name_table[sn].addr == p);
     debugTrace(DEBUG_stable, "cached stable name %ld at %p",sn,p);
-    stableUnlock();
+    stableNameUnlock();
     return sn;
   }
 
@@ -409,44 +224,15 @@ lookupStableName (StgPtr p)
   /* add the new stable name to the hash table */
   insertHashTable(addrToStableHash, (W_)p, (void *)sn);
 
-  stableUnlock();
+  stableNameUnlock();
 
   return sn;
 }
 
-StgStablePtr
-getStablePtr(StgPtr p)
-{
-  StgWord sp;
-
-  stableLock();
-  if (!stable_ptr_free) enlargeStablePtrTable();
-  sp = stable_ptr_free - stable_ptr_table;
-  stable_ptr_free  = (spEntry*)(stable_ptr_free->addr);
-  stable_ptr_table[sp].addr = p;
-  stableUnlock();
-  return (StgStablePtr)(sp);
-}
-
 /* -----------------------------------------------------------------------------
- * Treat stable pointers as roots for the garbage collector.
+ * Remember old stable name addresses
  * -------------------------------------------------------------------------- */
 
-#define FOR_EACH_STABLE_PTR(p, CODE)                                    \
-    do {                                                                \
-        spEntry *p;                                                     \
-        spEntry *__end_ptr = &stable_ptr_table[SPT_size];               \
-        for (p = stable_ptr_table; p < __end_ptr; p++) {                \
-            /* Internal pointers are free slots. NULL is last in free */ \
-            /* list. */                                                 \
-            if (p->addr &&                                              \
-                (p->addr < (P_)stable_ptr_table || p->addr >= (P_)__end_ptr)) \
-            {                                                           \
-                do { CODE } while(0);                                   \
-            }                                                           \
-        }                                                               \
-    } while(0)
-
 #define FOR_EACH_STABLE_NAME(p, CODE)                                   \
     do {                                                                \
         snEntry *p;                                                     \
@@ -468,31 +254,13 @@ getStablePtr(StgPtr p)
         }                                                               \
     } while(0)
 
-STATIC_INLINE void
-markStablePtrTable(evac_fn evac, void *user)
-{
-    FOR_EACH_STABLE_PTR(p, evac(user, (StgClosure **)&p->addr););
-}
-
-STATIC_INLINE void
+void
 rememberOldStableNameAddresses(void)
 {
     /* TODO: Only if !full GC */
     FOR_EACH_STABLE_NAME(p, p->old = p->addr;);
 }
 
-void
-markStableTables(evac_fn evac, void *user)
-{
-    /* Since no other thread can currently be dereferencing a stable pointer, it
-     * is safe to free the old versions of the table.
-     */
-    freeOldSPTs();
-
-    markStablePtrTable(evac, user);
-    rememberOldStableNameAddresses();
-}
-
 /* -----------------------------------------------------------------------------
  * Thread the stable pointer table for compacting GC.
  *
@@ -501,7 +269,7 @@ markStableTables(evac_fn evac, void *user)
  * collector may move the object it points to.
  * -------------------------------------------------------------------------- */
 
-STATIC_INLINE void
+void
 threadStableNameTable( evac_fn evac, void *user )
 {
     FOR_EACH_STABLE_NAME(p, {
@@ -514,19 +282,6 @@ threadStableNameTable( evac_fn evac, void *user )
     });
 }
 
-STATIC_INLINE void
-threadStablePtrTable( evac_fn evac, void *user )
-{
-    FOR_EACH_STABLE_PTR(p, evac(user, (StgClosure **)&p->addr););
-}
-
-void
-threadStableTables( evac_fn evac, void *user )
-{
-    threadStableNameTable(evac, user);
-    threadStablePtrTable(evac, user);
-}
-
 /* -----------------------------------------------------------------------------
  * Garbage collect any dead entries in the stable name table.
  *
@@ -542,7 +297,7 @@ threadStableTables( evac_fn evac, void *user )
  * -------------------------------------------------------------------------- */
 
 void
-gcStableTables( void )
+gcStableNameTable( void )
 {
     FOR_EACH_STABLE_NAME(
         p, {
@@ -579,7 +334,7 @@ gcStableTables( void )
  * -------------------------------------------------------------------------- */
 
 void
-updateStableTables(bool full)
+updateStableNameTable(bool full)
 {
     if (full && addrToStableHash != NULL && 0 != keyCountHashTable(addrToStableHash)) {
         freeHashTable(addrToStableHash,NULL);
diff --git a/rts/StableName.h b/rts/StableName.h
new file mode 100644 (file)
index 0000000..6b5e551
--- /dev/null
@@ -0,0 +1,31 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2004
+ *
+ * ---------------------------------------------------------------------------*/
+
+#pragma once
+
+#include "sm/GC.h" // for evac_fn below
+
+#include "BeginPrivate.h"
+
+void    initStableNameTable   ( void );
+void    exitStableNameTable      ( void );
+StgWord lookupStableName      ( StgPtr p );
+
+void    rememberOldStableNameAddresses ( void );
+
+void    threadStableNameTable ( evac_fn evac, void *user );
+void    gcStableNameTable     ( void );
+void    updateStableNameTable ( bool full );
+
+void    stableNameLock            ( void );
+void    stableNameUnlock          ( void );
+
+#if defined(THREADED_RTS)
+// needed by Schedule.c:forkProcess()
+extern Mutex stable_name_mutex;
+#endif
+
+#include "EndPrivate.h"
diff --git a/rts/StablePtr.c b/rts/StablePtr.c
new file mode 100644 (file)
index 0000000..0f53ffc
--- /dev/null
@@ -0,0 +1,329 @@
+/* -*- tab-width: 4 -*- */
+
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2002
+ *
+ * Stable pointers
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "PosixSource.h"
+#include "Rts.h"
+#include "RtsAPI.h"
+
+#include "Hash.h"
+#include "RtsUtils.h"
+#include "Trace.h"
+#include "StablePtr.h"
+
+#include <string.h>
+
+/* Comment from ADR's implementation in old RTS:
+
+  This files (together with @ghc/runtime/storage/PerformIO.lhc@ and a
+  small change in @HpOverflow.lc@) consists of the changes in the
+  runtime system required to implement "Stable Pointers". But we're
+  getting a bit ahead of ourselves --- what is a stable pointer and what
+  is it used for?
+
+  When Haskell calls C, it normally just passes over primitive integers,
+  floats, bools, strings, etc.  This doesn't cause any problems at all
+  for garbage collection because the act of passing them makes a copy
+  from the heap, stack or wherever they are onto the C-world stack.
+  However, if we were to pass a heap object such as a (Haskell) @String@
+  and a garbage collection occured before we finished using it, we'd run
+  into problems since the heap object might have been moved or even
+  deleted.
+
+  So, if a C call is able to cause a garbage collection or we want to
+  store a pointer to a heap object between C calls, we must be careful
+  when passing heap objects. Our solution is to keep a table of all
+  objects we've given to the C-world and to make sure that the garbage
+  collector collects these objects --- updating the table as required to
+  make sure we can still find the object.
+
+
+  Of course, all this rather begs the question: why would we want to
+  pass a boxed value?
+
+  One very good reason is to preserve laziness across the language
+  interface. Rather than evaluating an integer or a string because it
+  {\em might\/} be required by the C function, we can wait until the C
+  function actually wants the value and then force an evaluation.
+
+  Another very good reason (the motivating reason!) is that the C code
+  might want to execute an object of sort $IO ()$ for the side-effects
+  it will produce. For example, this is used when interfacing to an X
+  widgets library to allow a direct implementation of callbacks.
+
+  One final reason is that we may want to store composite Haskell
+  values in data structures implemented in the C side. Serializing and
+  deserializing these structures into unboxed form suitable for C may
+  be more expensive than maintaining the extra layer of indirection of
+  stable pointers.
+
+  The @makeStablePointer :: a -> IO (StablePtr a)@ function
+  converts a value into a stable pointer.  It is part of the @PrimIO@
+  monad, because we want to be sure we don't allocate one twice by
+  accident, and then only free one of the copies.
+
+  \begin{verbatim}
+  makeStablePtr#  :: a -> State# RealWorld -> (# RealWorld, a #)
+  freeStablePtr#  :: StablePtr# a -> State# RealWorld -> State# RealWorld
+  deRefStablePtr# :: StablePtr# a -> State# RealWorld ->
+        (# State# RealWorld, a #)
+  \end{verbatim}
+
+  There may be additional functions on the C side to allow evaluation,
+  application, etc of a stable pointer.
+
+  Stable Pointers are exported to the outside world as indices and not
+  pointers, because the stable pointer table is allowed to be
+  reallocated for growth. The table is never shrunk for its space to
+  be reclaimed.
+
+  Future plans for stable ptrs include distinguishing them by the
+  generation of the pointed object. See
+  http://ghc.haskell.org/trac/ghc/ticket/7670 for details.
+*/
+
+spEntry *stable_ptr_table = NULL;
+static spEntry *stable_ptr_free = NULL;
+static unsigned int SPT_size = 0;
+#define INIT_SPT_SIZE 64
+
+/* Each time the stable pointer table is enlarged, we temporarily retain the old
+ * version to ensure dereferences are thread-safe (see Note [Enlarging the
+ * stable pointer table]).  Since we double the size of the table each time, we
+ * can (theoretically) enlarge it at most N times on an N-bit machine.  Thus,
+ * there will never be more than N old versions of the table.
+ */
+#if SIZEOF_VOID_P == 4
+#define MAX_N_OLD_SPTS 32
+#elif SIZEOF_VOID_P == 8
+#define MAX_N_OLD_SPTS 64
+#else
+#error unknown SIZEOF_VOID_P
+#endif
+
+static spEntry *old_SPTs[MAX_N_OLD_SPTS];
+static uint32_t n_old_SPTs = 0;
+
+#if defined(THREADED_RTS)
+Mutex stable_ptr_mutex;
+#endif
+
+static void enlargeStablePtrTable(void);
+
+/* -----------------------------------------------------------------------------
+ * We must lock the StablePtr table during GC, to prevent simultaneous
+ * calls to freeStablePtr().
+ * -------------------------------------------------------------------------- */
+
+void
+stablePtrLock(void)
+{
+    initStablePtrTable();
+    ACQUIRE_LOCK(&stable_ptr_mutex);
+}
+
+void
+stablePtrUnlock(void)
+{
+    RELEASE_LOCK(&stable_ptr_mutex);
+}
+
+/* -----------------------------------------------------------------------------
+ * Initialising the table
+ * -------------------------------------------------------------------------- */
+
+STATIC_INLINE void
+initSpEntryFreeList(spEntry *table, uint32_t n, spEntry *free)
+{
+  spEntry *p;
+  for (p = table + n - 1; p >= table; p--) {
+      p->addr = (P_)free;
+      free = p;
+  }
+  stable_ptr_free = table;
+}
+
+void
+initStablePtrTable(void)
+{
+    if (SPT_size > 0) return;
+    SPT_size = INIT_SPT_SIZE;
+    stable_ptr_table = stgMallocBytes(SPT_size * sizeof(spEntry),
+                                      "initStablePtrTable");
+    initSpEntryFreeList(stable_ptr_table,INIT_SPT_SIZE,NULL);
+
+#if defined(THREADED_RTS)
+    initMutex(&stable_ptr_mutex);
+#endif
+}
+
+/* -----------------------------------------------------------------------------
+ * Enlarging the table
+ * -------------------------------------------------------------------------- */
+
+// Must be holding stable_ptr_mutex
+static void
+enlargeStablePtrTable(void)
+{
+    uint32_t old_SPT_size = SPT_size;
+    spEntry *new_stable_ptr_table;
+
+    // 2nd and subsequent times
+    SPT_size *= 2;
+
+    /* We temporarily retain the old version instead of freeing it; see Note
+     * [Enlarging the stable pointer table].
+     */
+    new_stable_ptr_table =
+        stgMallocBytes(SPT_size * sizeof(spEntry),
+                       "enlargeStablePtrTable");
+    memcpy(new_stable_ptr_table,
+           stable_ptr_table,
+           old_SPT_size * sizeof(spEntry));
+    ASSERT(n_old_SPTs < MAX_N_OLD_SPTS);
+    old_SPTs[n_old_SPTs++] = stable_ptr_table;
+
+    /* When using the threaded RTS, the update of stable_ptr_table is assumed to
+     * be atomic, so that another thread simultaneously dereferencing a stable
+     * pointer will always read a valid address.
+     */
+    stable_ptr_table = new_stable_ptr_table;
+
+    initSpEntryFreeList(stable_ptr_table + old_SPT_size, old_SPT_size, NULL);
+}
+
+/* Note [Enlarging the stable pointer table]
+ *
+ * To enlarge the stable pointer table, we allocate a new table, copy the
+ * existing entries, and then store the old version of the table in old_SPTs
+ * until we free it during GC.  By not immediately freeing the old version
+ * (or equivalently by not growing the table using realloc()), we ensure that
+ * another thread simultaneously dereferencing a stable pointer using the old
+ * version can safely access the table without causing a segfault (see Trac
+ * #10296).
+ *
+ * Note that because the stable pointer table is doubled in size each time it is
+ * enlarged, the total memory needed to store the old versions is always less
+ * than that required to hold the current version.
+ */
+
+
+/* -----------------------------------------------------------------------------
+ * Freeing entries and tables
+ * -------------------------------------------------------------------------- */
+
+static void
+freeOldSPTs(void)
+{
+    uint32_t i;
+
+    for (i = 0; i < n_old_SPTs; i++) {
+        stgFree(old_SPTs[i]);
+    }
+    n_old_SPTs = 0;
+}
+
+void
+exitStablePtrTable(void)
+{
+    if (stable_ptr_table)
+        stgFree(stable_ptr_table);
+    stable_ptr_table = NULL;
+    SPT_size = 0;
+
+    freeOldSPTs();
+
+#if defined(THREADED_RTS)
+    closeMutex(&stable_ptr_mutex);
+#endif
+}
+
+STATIC_INLINE void
+freeSpEntry(spEntry *sp)
+{
+    sp->addr = (P_)stable_ptr_free;
+    stable_ptr_free = sp;
+}
+
+void
+freeStablePtrUnsafe(StgStablePtr sp)
+{
+    ASSERT((StgWord)sp < SPT_size);
+    freeSpEntry(&stable_ptr_table[(StgWord)sp]);
+}
+
+void
+freeStablePtr(StgStablePtr sp)
+{
+    stablePtrLock();
+    freeStablePtrUnsafe(sp);
+    stablePtrUnlock();
+}
+
+/* -----------------------------------------------------------------------------
+ * Looking up
+ * -------------------------------------------------------------------------- */
+
+StgStablePtr
+getStablePtr(StgPtr p)
+{
+  StgWord sp;
+
+  stablePtrLock();
+  if (!stable_ptr_free) enlargeStablePtrTable();
+  sp = stable_ptr_free - stable_ptr_table;
+  stable_ptr_free  = (spEntry*)(stable_ptr_free->addr);
+  stable_ptr_table[sp].addr = p;
+  stablePtrUnlock();
+  return (StgStablePtr)(sp);
+}
+
+/* -----------------------------------------------------------------------------
+ * Treat stable pointers as roots for the garbage collector.
+ * -------------------------------------------------------------------------- */
+
+#define FOR_EACH_STABLE_PTR(p, CODE)                                    \
+    do {                                                                \
+        spEntry *p;                                                     \
+        spEntry *__end_ptr = &stable_ptr_table[SPT_size];               \
+        for (p = stable_ptr_table; p < __end_ptr; p++) {                \
+            /* Internal pointers are free slots. NULL is last in free */ \
+            /* list. */                                                 \
+            if (p->addr &&                                              \
+                (p->addr < (P_)stable_ptr_table || p->addr >= (P_)__end_ptr)) \
+            {                                                           \
+                do { CODE } while(0);                                   \
+            }                                                           \
+        }                                                               \
+    } while(0)
+
+void
+markStablePtrTable(evac_fn evac, void *user)
+{
+    /* Since no other thread can currently be dereferencing a stable pointer, it
+     * is safe to free the old versions of the table.
+     */
+    freeOldSPTs();
+
+    FOR_EACH_STABLE_PTR(p, evac(user, (StgClosure **)&p->addr););
+}
+
+/* -----------------------------------------------------------------------------
+ * Thread the stable pointer table for compacting GC.
+ *
+ * Here we must call the supplied evac function for each pointer into
+ * the heap from the stable tables, because the compacting
+ * collector may move the object it points to.
+ * -------------------------------------------------------------------------- */
+
+void
+threadStablePtrTable( evac_fn evac, void *user )
+{
+    FOR_EACH_STABLE_PTR(p, evac(user, (StgClosure **)&p->addr););
+}
similarity index 54%
rename from rts/Stable.h
rename to rts/StablePtr.h
index 399a2b3..3fb305b 100644 (file)
 
 void    freeStablePtr         ( StgStablePtr sp );
 
-/* Use the "Unsafe" one after manually locking with stableLock/stableUnlock */
+/* Use the "Unsafe" one after only when manually locking and
+   unlocking with stablePtrLock/stablePtrUnlock */
 void    freeStablePtrUnsafe   ( StgStablePtr sp );
 
-void    initStableTables      ( void );
-void    exitStableTables      ( void );
-StgWord lookupStableName      ( StgPtr p );
+void    initStablePtrTable      ( void );
+void    exitStablePtrTable      ( void );
 
-/* Call given function on every stable ptr. markStableTables depends
+/* Call given function on every stable ptr. markStablePtrTable depends
  * on the function updating its pointers in case the object is
- * moved. */
-/* TODO: This also remembers old stable name addresses, which isn't
- * necessary in some contexts markStableTables is called from.
- * Consider splitting it.
+ * moved.
  */
-void    markStableTables      ( evac_fn evac, void *user );
+void    markStablePtrTable    ( evac_fn evac, void *user );
 
-void    threadStableTables    ( evac_fn evac, void *user );
-void    gcStableTables        ( void );
-void    updateStableTables    ( bool full );
+void    threadStablePtrTable  ( evac_fn evac, void *user );
 
-void    stableLock            ( void );
-void    stableUnlock          ( void );
+void    stablePtrLock         ( void );
+void    stablePtrUnlock       ( void );
 
 #if defined(THREADED_RTS)
 // needed by Schedule.c:forkProcess()
-extern Mutex stable_mutex;
+extern Mutex stable_ptr_mutex;
 #endif
 
 #include "EndPrivate.h"
index 7711377..0b22440 100644 (file)
@@ -12,7 +12,7 @@
 #include "Rts.h"
 #include "RtsUtils.h"
 #include "Hash.h"
-#include "Stable.h"
+#include "StablePtr.h"
 
 static HashTable * spt = NULL;
 
index 8e868e6..c0ac936 100644 (file)
@@ -1,5 +1,5 @@
 #include "Rts.h"
-#include "Stable.h"
+#include "StablePtr.h"
 #include "TopHandler.h"
 
 #if defined(THREADED_RTS)
index 1146eea..d724354 100644 (file)
@@ -13,7 +13,6 @@
 #include <rts/Types.h>
 #include <rts/storage/Closures.h>
 #include <stg/Types.h>
-#include <rts/Stable.h>
 
 // Initialize the top handler subsystem
 void initTopHandler(void);
index 4cd1e38..f033870 100644 (file)
@@ -15,7 +15,6 @@
 #include "RtsUtils.h"
 #include "Prelude.h"
 #include "Ticker.h"
-#include "Stable.h"
 #include "ThreadLabels.h"
 #include "Libdw.h"
 
index d41135d..d509953 100644 (file)
@@ -127,7 +127,8 @@ library
                       rts/Profiling.h
                       rts/Signals.h
                       rts/SpinLock.h
-                      rts/Stable.h
+                      rts/StableName.h
+                      rts/StablePtr.h
                       rts/StaticPtrTable.h
                       rts/TTY.h
                       rts/Threads.h
@@ -393,7 +394,8 @@ library
                STM.c
                Schedule.c
                Sparks.c
-               Stable.c
+               StableName.c
+               StablePtr.c
                StaticPtrTable.c
                Stats.c
                StgCRun.c
index 10ad73c..004e042 100644 (file)
@@ -25,7 +25,8 @@
 #include "Trace.h"
 #include "Weak.h"
 #include "MarkWeak.h"
-#include "Stable.h"
+#include "StablePtr.h"
+#include "StableName.h"
 
 // Turn off inlining when debugging - it obfuscates things
 #if defined(DEBUG)
@@ -1000,7 +1001,10 @@ compact(StgClosure *static_objects)
     thread_static(static_objects /* ToDo: ok? */);
 
     // the stable pointer table
-    threadStableTables((evac_fn)thread_root, NULL);
+    threadStablePtrTable((evac_fn)thread_root, NULL);
+
+    // the stable name table
+    threadStableNameTable((evac_fn)thread_root, NULL);
 
     // the CAF list (used by GHCi)
     markCAFs((evac_fn)thread_root, NULL);
index 90857ab..70d6d8e 100644 (file)
@@ -46,7 +46,8 @@
 #include "RetainerProfile.h"
 #include "LdvProfile.h"
 #include "RaiseAsync.h"
-#include "Stable.h"
+#include "StableName.h"
+#include "StablePtr.h"
 #include "CheckUnload.h"
 #include "CNF.h"
 #include "RtsFlags.h"
@@ -238,8 +239,9 @@ GarbageCollect (uint32_t collect_gen,
   // tell the stats department that we've started a GC
   stat_startGC(cap, gct);
 
-  // lock the StablePtr table
-  stableLock();
+  // Lock the StablePtr table. This prevents FFI calls manipulating
+  // the table from occurring during GC.
+  stablePtrLock();
 
 #if defined(DEBUG)
   mutlist_MUTVARS = 0;
@@ -405,7 +407,10 @@ GarbageCollect (uint32_t collect_gen,
   initWeakForGC();
 
   // Mark the stable pointer table.
-  markStableTables(mark_root, gct);
+  markStablePtrTable(mark_root, gct);
+
+  // Remember old stable name addresses.
+  rememberOldStableNameAddresses ();
 
   /* -------------------------------------------------------------------------
    * Repeatedly scavenge all the areas we know about until there's no
@@ -431,7 +436,7 @@ GarbageCollect (uint32_t collect_gen,
   shutdown_gc_threads(gct->thread_index, idle_cap);
 
   // Now see which stable names are still alive.
-  gcStableTables();
+  gcStableNameTable();
 
 #if defined(THREADED_RTS)
   if (n_gc_threads == 1) {
@@ -730,15 +735,15 @@ GarbageCollect (uint32_t collect_gen,
   if (major_gc) { gcCAFs(); }
 #endif
 
-  // Update the stable pointer hash table.
-  updateStableTables(major_gc);
+  // Update the stable name hash table
+  updateStableNameTable(major_gc);
 
   // unlock the StablePtr table.  Must be before scheduleFinalizers(),
   // because a finalizer may call hs_free_fun_ptr() or
   // hs_free_stable_ptr(), both of which access the StablePtr table.
-  stableUnlock();
+  stablePtrUnlock();
 
-  // Must be after stableUnlock(), because it might free stable ptrs.
+  // Must be after stablePtrUnlock(), because it might free stable ptrs.
   if (major_gc) {
       checkUnload (gct->scavenged_static_objects);
   }
index 84de914..5d5dbc4 100644 (file)
@@ -724,7 +724,7 @@ getWanted verbose os tmpdir gccProgram gccFlags nmProgram mobjdumpProgram
                      "",
                      "#include \"PosixSource.h\"",
                      "#include \"Rts.h\"",
-                     "#include \"Stable.h\"",
+                     "#include \"StableName.h\"",
                      "#include \"Capability.h\"",
                      "",
                      "#include <inttypes.h>",