📄 prmsgc.c
字号:
}static void NotifyFinalizer(void){ if (!PR_CLIST_IS_EMPTY(&_pr_finalQueue)) { PR_ASSERT( GC_IS_LOCKED() ); PR_Notify(_pr_gcData.lock); }}void _PR_CreateFinalizer(PRThreadScope scope){ if (!_pr_gcData.finalizer) { _pr_gcData.finalizer = PR_CreateThreadGCAble(PR_SYSTEM_THREAD, FinalizerLoop, 0, PR_PRIORITY_LOW, scope, PR_UNJOINABLE_THREAD, 0); if (_pr_gcData.finalizer == NULL) /* We are doomed if we can't start the finalizer */ PR_Abort(); }}void pr_FinalizeOnExit(void){#ifdef DEBUG_warren OutputDebugString("### Doing finalize-on-exit pass\n");#endif PR_ForceFinalize();#ifdef DEBUG_warren OutputDebugString("### Finalize-on-exit complete. Dumping object left to memory.out\n"); PR_DumpMemorySummary(); PR_DumpMemory(PR_TRUE);#endif}PR_IMPLEMENT(void) PR_ForceFinalize(){ LOCK_GC(); NotifyFinalizer(); while (!PR_CLIST_IS_EMPTY(&_pr_finalQueue)) { PR_ASSERT( GC_IS_LOCKED() ); (void) PR_Wait(_pr_gcData.lock, PR_INTERVAL_NO_TIMEOUT); } UNLOCK_GC(); /* XXX I don't know how to make it wait (yet) */}/************************************************************************/typedef struct GCWeakStr { PRCList links; PRWord *object;} GCWeak;/*** Find pointer to GCWeak struct from the list linkaged embedded in it*/#define WeakPtr(_qp) \ ((GCWeak*) ((char*) (_qp) - offsetof(GCWeak,links)))PRCList _pr_weakLinks = PR_INIT_STATIC_CLIST(&_pr_weakLinks);PRCList _pr_freeWeakLinks = PR_INIT_STATIC_CLIST(&_pr_freeWeakLinks);#define WEAK_FREELIST_ISEMPTY() (_pr_freeWeakLinks.next == &_pr_freeWeakLinks)/* * Keep objects referred to by weak free list alive until they can be * freed */static void PR_CALLBACK ScanWeakFreeList(void *notused) {#ifdef XP_MAC#pragma unused (notused)#endif PRCList *qp = _pr_freeWeakLinks.next; while (qp != &_pr_freeWeakLinks) { GCWeak *wp = WeakPtr(qp); qp = qp->next; ProcessRootPointer(wp->object); }}/* * Empty the list of weak objects. Note that we can't call malloc/free * under the cover of the GC's lock (we might deadlock), so transfer the * list of free objects to a local list under the cover of the lock, then * release the lock and free up the memory. */static void EmptyWeakFreeList(void) { if (!WEAK_FREELIST_ISEMPTY()) { PRCList *qp, freeLinks; PR_INIT_CLIST(&freeLinks); /* * Transfer list of free weak links from the global list to a * local list. */ LOCK_GC(); qp = _pr_freeWeakLinks.next; while (qp != &_pr_freeWeakLinks) { GCWeak *wp = WeakPtr(qp); qp = qp->next; PR_REMOVE_LINK(&wp->links); PR_APPEND_LINK(&wp->links, &freeLinks); } UNLOCK_GC(); /* Free up storage now */ qp = freeLinks.next; while (qp != &freeLinks) { GCWeak *wp = WeakPtr(qp); qp = qp->next; PR_DELETE(wp); } }}/* * Allocate a new weak node in the weak objects list */static GCWeak *AllocWeakNode(void){ EmptyWeakFreeList(); return PR_NEWZAP(GCWeak);}static void FreeWeakNode(GCWeak *node){ PR_DELETE(node);}/* * Check the weak links for validity. Note that the list of weak links is * itself weak (otherwise we would keep the objects with weak links in * them alive forever). As we scan the list check the weak link object * itself and if it's not marked then remove it from the weak link list */static void CheckWeakLinks(void) { PRCList *qp; GCWeak *wp; PRWord *p, h, tix, **weakPtrAddress; CollectorType *ct; PRUint32 offset; qp = _pr_weakLinks.next; while (qp != &_pr_weakLinks) { wp = WeakPtr(qp); qp = qp->next; if ((p = wp->object) != 0) { h = p[0]; /* Grab header word */ if ((h & MARK_BIT) == 0) { /* * The object that has a weak link is no longer being * referenced; remove it from the chain and let it get * swept away by the GC. Transfer it to the list of * free weak links for later freeing. */ PR_REMOVE_LINK(&wp->links); PR_APPEND_LINK(&wp->links, &_pr_freeWeakLinks); collectorCleanupNeeded = 1; continue; } /* Examine a live object that contains weak links */ tix = GET_TYPEIX(h); ct = &_pr_collectorTypes[tix]; PR_ASSERT((ct->flags != 0) && (ct->gctype.getWeakLinkOffset != 0)); if (0 == ct->gctype.getWeakLinkOffset) { /* Heap is probably corrupted */ continue; } /* Get offset into the object of where the weak pointer is */ offset = (*ct->gctype.getWeakLinkOffset)(p + 1); /* Check the weak pointer */ weakPtrAddress = (PRWord**)((char*)(p + 1) + offset); p = *weakPtrAddress; if (p != 0) { h = p[-1]; /* Grab header word for pointed to object */ if (h & MARK_BIT) { /* Object can't be dead */ continue; } /* Break weak link to an object that is about to be swept */ *weakPtrAddress = 0; } } }}/************************************************************************//*** Perform a complete garbage collection*/extern GCLockHook *_pr_GCLockHook;static void dogc(void){ RootFinder *rf; GCLockHook* lhook; GCScanQ scanQ; GCSeg *sp, *esp; PRInt64 start, end, diff;#if defined(GCMETER) || defined(GCTIMINGHOOK) start = PR_Now();#endif /* ** Stop all of the other threads. This also promises to capture the ** register state of each and every thread */ /* ** Get all the locks that will be need during GC after SuspendAll. We ** cannot make any locking/library calls after SuspendAll. */ if (_pr_GCLockHook) { for (lhook = _pr_GCLockHook->next; lhook != _pr_GCLockHook; lhook = lhook->next) { (*lhook->func)(PR_GCBEGIN, lhook->arg); } } PR_SuspendAll();#ifdef GCMETER /* Reset meter info */ if (_pr_gcMeter & _GC_METER_STATS) { fprintf(stderr, "[GCSTATS: busy:%ld skipped:%ld, alloced:%ld+wasted:%ld+free:%ld = total:%ld]\n", (long) _pr_gcData.busyMemory, (long) meter.skippedFreeChunks, (long) meter.allocBytes, (long) meter.wastedBytes, (long) _pr_gcData.freeMemory, (long) _pr_gcData.allocMemory); } memset(&meter, 0, sizeof(meter));#endif PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("begin mark phase; busy=%d free=%d total=%d", _pr_gcData.busyMemory, _pr_gcData.freeMemory, _pr_gcData.allocMemory)); if (_pr_beginGCHook) { (*_pr_beginGCHook)(_pr_beginGCHookArg); } /* ** Initialize scanQ to all zero's so that root finder doesn't walk ** over it... */ memset(&scanQ, 0, sizeof(scanQ)); pScanQ = &scanQ; /******************************************/ /* MARK PHASE */ EmptyFreelists(); /* Find root's */ PR_LOG(_pr_msgc_lm, PR_LOG_WARNING, ("begin mark phase; busy=%d free=%d total=%d", _pr_gcData.busyMemory, _pr_gcData.freeMemory, _pr_gcData.allocMemory)); METER(_pr_scanDepth = 0); rf = _pr_rootFinders; while (rf) { _GCTRACE(GC_ROOTS, ("finding roots in %s", rf->name)); (*rf->func)(rf->arg); rf = rf->next; } _GCTRACE(GC_ROOTS, ("done finding roots")); /* Scan remaining object's that need scanning */ ScanScanQ(&scanQ); PR_ASSERT(pScanQ == &scanQ); PR_ASSERT(scanQ.queued == 0); METER({ if (_pr_scanDepth > _pr_maxScanDepth) { _pr_maxScanDepth = _pr_scanDepth; } }); /******************************************/ /* FINALIZATION PHASE */ METER(_pr_scanDepth = 0); PrepareFinalize(); /* Scan any resurrected objects found during finalization */ ScanScanQ(&scanQ); PR_ASSERT(pScanQ == &scanQ); PR_ASSERT(scanQ.queued == 0); METER({ if (_pr_scanDepth > _pr_maxScanDepth) { _pr_maxScanDepth = _pr_scanDepth; } }); pScanQ = 0; /******************************************/ /* SWEEP PHASE */ /* ** Sweep each segment clean. While we are at it, figure out which ** segment has the most free space and make that the current segment. */ CheckWeakLinks(); _GCTRACE(GC_SWEEP, ("begin sweep phase")); _pr_gcData.freeMemory = 0; _pr_gcData.busyMemory = 0; sp = segs; esp = sp + nsegs; while (sp < esp) { if (SweepSegment(sp)) { /* ** Segment is now free and has been replaced with a different ** segment object. */ esp--; continue; } sp++; }#if defined(GCMETER) || defined(GCTIMINGHOOK) end = PR_Now();#endif#ifdef GCMETER LL_SUB(diff, end, start); PR_LOG(GC, PR_LOG_ALWAYS, ("done; busy=%d free=%d chunks=%d total=%d time=%lldms", _pr_gcData.busyMemory, _pr_gcData.freeMemory, meter.numFreeChunks, _pr_gcData.allocMemory, diff)); if (_pr_gcMeter & _GC_METER_FREE_LIST) { PRIntn bin; fprintf(stderr, "Freelist bins:\n"); for (bin = 0; bin < NUM_BINS; bin++) { GCFreeChunk *cp = bins[bin]; while (cp != NULL) { fprintf(stderr, "%3d: %p %8ld\n", bin, cp, (long) cp->chunkSize); cp = cp->next; } } }#endif if (_pr_endGCHook) { (*_pr_endGCHook)(_pr_endGCHookArg); } /* clear the running total of the bytes allocated via BigAlloc() */ bigAllocBytes = 0; /* And resume multi-threading */ PR_ResumeAll(); if (_pr_GCLockHook) { for (lhook = _pr_GCLockHook->prev; lhook != _pr_GCLockHook; lhook = lhook->prev) { (*lhook->func)(PR_GCEND, lhook->arg); } } /* Kick finalizer */ NotifyFinalizer();#ifdef GCTIMINGHOOK if (_pr_gcData.gcTimingHook) { PRInt32 time; LL_SUB(diff, end, start); LL_L2I(time, diff); _pr_gcData.gcTimingHook(time); }#endif}PR_IMPLEMENT(void) PR_GC(void){ LOCK_GC(); dogc(); UNLOCK_GC(); EmptyWeakFreeList();}/******************************************************************************* * Heap Walker ******************************************************************************//*** This is yet another disgusting copy of the body of ProcessRootPointer** (the other being ProcessRootBlock), but we're not leveraging a single** function in their cases in interest of performance (avoiding the function** call).*/static PRInt32 PR_CALLBACKpr_ConservativeWalkPointer(void* ptr, PRWalkFun walkRootPointer, void* data){ PRWord *p0, *p, *segBase; GCSeg* sp; p0 = (PRWord*) ptr; /* ** XXX: ** Until Win16 maintains lowSeg and highSeg correctly, ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs)) ** Allways scan through the segment list */#if !defined(WIN16) if (p0 < _pr_gcData.lowSeg) return 0; /* below gc heap */ if (p0 >= _pr_gcData.highSeg) return 0; /* above gc heap */#endif /* NOTE: inline expansion of InHeap */ /* Find segment */ sp = lastInHeap; if (!sp || !IN_SEGMENT(sp,p0)) { GCSeg *esp; sp = segs; esp = segs + nsegs; for (; sp < esp; sp++) { if (IN_SEGMENT(sp, p0)) { lastInHeap = sp; goto find_object; } } return 0; } find_object: /* NOTE: Inline expansion of FindObject */ /* Align p to it's proper boundary before we start fiddling with it */ p = (PRWord*) ((PRWord)p0 & ~(BYTES_PER_WORD-1L)); segBase = (PRWord *) sp->base; do { if (IS_HBIT(sp, p)) { goto winner; } p--; } while (p >= segBase); /* ** We have a pointer into the heap, but it has no header ** bit. This means that somehow the very first object in the heap ** doesn't have a header. This is impossible so when debugging ** lets abort. */#ifdef DEBUG PR_Abort();#endif return 0; winner: return walkRootPointer(p, data);}static PRInt32 PR_CALLBACKpr_ConservativeWalkBlock(void **base, PRInt32 count, PRWalkFun walkRootPointer, void* data){ PRWord *p0; while (--count >= 0) { PRInt32 status; p0 = (PRWord*) *base++; status = pr_ConservativeWalkPointer(p0, walkRootPointer, data); if (status) return status; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -