diff options
author | Simon Marlow <marlowsd@gmail.com> | 2015-06-08 11:54:51 +0100 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2015-06-08 11:59:22 +0100 |
commit | 19ec6a84d6344c2808d0d41da11956689a0e4ae9 (patch) | |
tree | e83ad4f659c4f6323b91d6e562bd1cdf7bacf765 /rts/sm/Storage.c | |
parent | 89223ce1340654455a9f3aa9cbf25f30884227fd (diff) | |
download | haskell-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.c | 41 |
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. -------------------------------------------------------------------------- */ |