summaryrefslogtreecommitdiff
path: root/rts/sm/Storage.c
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2015-06-08 11:54:51 +0100
committerSimon Marlow <marlowsd@gmail.com>2015-06-08 11:59:22 +0100
commit19ec6a84d6344c2808d0d41da11956689a0e4ae9 (patch)
treee83ad4f659c4f6323b91d6e562bd1cdf7bacf765 /rts/sm/Storage.c
parent89223ce1340654455a9f3aa9cbf25f30884227fd (diff)
downloadhaskell-19ec6a84d6344c2808d0d41da11956689a0e4ae9.tar.gz
Fix for CAF retention when dynamically loading & unloading code
In a situaion where we have some statically-linked code and we want to load and unload a series of objects, we need the CAFs in the statically-linked code to be retained indefinitely, while the CAFs in the dynamically-linked code should be GC'd as normal, so that we can detect when the code is unloadable. This was wrong before - we GC'd CAFs in the static code, leading to a crash in the rare case where we use a CAF, GC it, and then load a new object that uses it again. I also did some tidy up: RtsConfig now has a field keep_cafs to indicate whether we want CAFs to be retained in static code.
Diffstat (limited to 'rts/sm/Storage.c')
-rw-r--r--rts/sm/Storage.c41
1 files changed, 34 insertions, 7 deletions
diff --git a/rts/sm/Storage.c b/rts/sm/Storage.c
index 85884fa12d..77796013ce 100644
--- a/rts/sm/Storage.c
+++ b/rts/sm/Storage.c
@@ -416,8 +416,8 @@ newCAF(StgRegTable *reg, StgIndStatic *caf)
{
// Note [dyn_caf_list]
// If we are in GHCi _and_ we are using dynamic libraries,
- // then we can't redirect newCAF calls to newDynCAF (see below),
- // so we make newCAF behave almost like newDynCAF.
+ // then we can't redirect newCAF calls to newRetainedCAF (see below),
+ // so we make newCAF behave almost like newRetainedCAF.
// The dynamic libraries might be used by both the interpreted
// program and GHCi itself, so they must not be reverted.
// This also means that in GHCi with dynamic libraries, CAFs are not
@@ -464,17 +464,17 @@ setKeepCAFs (void)
keepCAFs = 1;
}
-// An alternate version of newCaf which is used for dynamically loaded
+// An alternate version of newCAF which is used for dynamically loaded
// object code in GHCi. In this case we want to retain *all* CAFs in
// the object code, because they might be demanded at any time from an
// expression evaluated on the command line.
// Also, GHCi might want to revert CAFs, so we add these to the
// revertible_caf_list.
//
-// The linker hackily arranges that references to newCaf from dynamic
-// code end up pointing to newDynCAF.
-StgInd *
-newDynCAF (StgRegTable *reg, StgIndStatic *caf)
+// The linker hackily arranges that references to newCAF from dynamic
+// code end up pointing to newRetainedCAF.
+//
+StgInd* newRetainedCAF (StgRegTable *reg, StgIndStatic *caf)
{
StgInd *bh;
@@ -491,6 +491,33 @@ newDynCAF (StgRegTable *reg, StgIndStatic *caf)
return bh;
}
+// If we are using loadObj/unloadObj in the linker, then we want to
+//
+// - retain all CAFs in statically linked code (keepCAFs == rtsTrue),
+// because we might link a new object that uses any of these CAFs.
+//
+// - GC CAFs in dynamically-linked code, so that we can detect when
+// a dynamically-linked object is unloadable.
+//
+// So for this case, we set keepCAFs to rtsTrue, and link newCAF to newGCdCAF
+// for dynamically-linked code.
+//
+StgInd* newGCdCAF (StgRegTable *reg, StgIndStatic *caf)
+{
+ StgInd *bh;
+
+ bh = lockCAF(reg, caf);
+ if (!bh) return NULL;
+
+ // Put this CAF on the mutable list for the old generation.
+ if (oldest_gen->no != 0) {
+ recordMutableCap((StgClosure*)caf,
+ regTableToCapability(reg), oldest_gen->no);
+ }
+
+ return bh;
+}
+
/* -----------------------------------------------------------------------------
Nursery management.
-------------------------------------------------------------------------- */