StgWord newCAF(StgRegTable *reg, StgClosure *caf, StgClosure *bh) { if (lockCAF(caf,bh) == 0) return 0; if(keepCAFs) { // HACK: // 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. // 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 // garbage collected. If this turns out to be a problem, we could // do another hack here and do an address range test on caf to figure // out whether it is from a dynamic library. ACQUIRE_SM_LOCK; // caf_list is global, locked by sm_mutex ((StgIndStatic *)caf)->static_link = caf_list; caf_list = caf; RELEASE_SM_LOCK; } else { // Put this CAF on the mutable list for the old generation. ((StgIndStatic *)caf)->saved_info = NULL; if (oldest_gen->no != 0) { recordMutableCap(caf, regTableToCapability(reg), oldest_gen->no); } } return 1; }
StgInd * newCAF(StgRegTable *reg, StgIndStatic *caf) { StgInd *bh; bh = lockCAF(reg, caf); if (!bh) return NULL; if(keepCAFs) { // Note [dyn_caf_list] // If we are in GHCi _and_ we are using dynamic libraries, // 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 // garbage collected. If this turns out to be a problem, we could // do another hack here and do an address range test on caf to figure // out whether it is from a dynamic library. ACQUIRE_SM_LOCK; // dyn_caf_list is global, locked by sm_mutex caf->static_link = (StgClosure*)dyn_caf_list; dyn_caf_list = (StgIndStatic*)((StgWord)caf | STATIC_FLAG_LIST); RELEASE_SM_LOCK; } else { // Put this CAF on the mutable list for the old generation. if (oldest_gen->no != 0) { recordMutableCap((StgClosure*)caf, regTableToCapability(reg), oldest_gen->no); } #ifdef DEBUG // In the DEBUG rts, we keep track of live CAFs by chaining them // onto a list debug_caf_list. This is so that we can tell if we // ever enter a GC'd CAF, and emit a suitable barf(). // // The saved_info field of the CAF is used as the link field for // debug_caf_list, because this field is only used by newDynCAF // for revertible CAFs, and we don't put those on the // debug_caf_list. ACQUIRE_SM_LOCK; // debug_caf_list is global, locked by sm_mutex ((StgIndStatic *)caf)->saved_info = (const StgInfoTable*)debug_caf_list; debug_caf_list = (StgIndStatic*)caf; RELEASE_SM_LOCK; #endif } 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; }