📄 prmsgc.c
字号:
if (!base) { PR_DELETE(segInfo); return 0; } nhbits = (PRInt32)( (allocSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2); nhbytes = ((nhbits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2) * sizeof(PRWord); /* Get bitmap memory from malloc heap */#if defined(WIN16) PR_ASSERT( nhbytes < MAX_ALLOC_SIZE );#endif hbits = (PRWord *) PR_CALLOC((PRUint32)nhbytes); if (!hbits) { /* Loser! */ PR_DELETE(segInfo); if (exactly) { PR_DELETE(base); } else { /* XXX do something about this */ /* _MD_FreeGCSegment(base, allocSize); */ } return 0; } /* ** Setup new segment. */ sp = &segs[nsegs++]; segInfo->base = sp->base = base; segInfo->limit = sp->limit = base + allocSize; segInfo->hbits = sp->hbits = hbits; sp->info = segInfo; segInfo->fromMalloc = exactly; memset(base, 0, allocSize);#ifdef GCMETER if (_pr_gcMeter & _GC_METER_GROWTH) { fprintf(stderr, "[GC: new segment base=%p size=%ld]\n", sp->base, (long) allocSize); }#endif _pr_gcData.allocMemory += allocSize; _pr_gcData.freeMemory += allocSize; if (!exactly) { PRInt32 bin; /* Put free memory into a freelist bin */ cp = (GCFreeChunk *) base; cp->segment = sp; cp->chunkSize = allocSize; InlineBinNumber(bin, allocSize) cp->next = bins[bin]; bins[bin] = cp; if (bin < minBin) minBin = bin; if (bin > maxBin) maxBin = bin; } else { /* ** When exactly allocating the entire segment is given over to a ** single object to prevent fragmentation */ } if (!_pr_gcData.lowSeg) { _pr_gcData.lowSeg = (PRWord*) sp->base; _pr_gcData.highSeg = (PRWord*) sp->limit; } else { if ((PRWord*)sp->base < _pr_gcData.lowSeg) { _pr_gcData.lowSeg = (PRWord*) sp->base; } if ((PRWord*)sp->limit > _pr_gcData.highSeg) { _pr_gcData.highSeg = (PRWord*) sp->limit; } } /* ** Get rid of the GC pointer in case it shows up in some uninitialized ** local stack variable later (while scanning the C stack looking for ** roots). */ memset(&base, 0, sizeof(base)); /* optimizers beware */ PR_LOG(_pr_msgc_lm, PR_LOG_WARNING, ("grow heap: total gc memory now %d", _pr_gcData.allocMemory)); return sp;}#ifdef USE_EXTEND_HEAPstatic PRBool ExtendHeap(PRInt32 requestedSize) { GCSeg* sp; PRUint32 allocSize; PRInt32 oldSize, newSize; PRInt32 newHBits, newHBytes; PRInt32 oldHBits, oldHBytes; PRWord* hbits; GCFreeChunk* cp; PRInt32 bin; /* Can't extend nothing */ if (nsegs == 0) return PR_FALSE; /* Round up requested size to the size of a page */ allocSize = (PRUint32) requestedSize; allocSize = (allocSize + _pr_pageSize - 1L) >> _pr_pageShift; allocSize <<= _pr_pageShift; /* Malloc some memory for the new hbits array */ sp = segs; oldSize = sp->limit - sp->base; newSize = oldSize + allocSize; newHBits = (newSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2; newHBytes = ((newHBits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2) * sizeof(PRWord); hbits = (PRWord*) PR_MALLOC(newHBytes); if (0 == hbits) return PR_FALSE; /* Attempt to extend the last segment by the desired amount */ if (_MD_ExtendGCHeap(sp->base, oldSize, newSize)) { oldHBits = (oldSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2; oldHBytes = ((oldHBits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2) * sizeof(PRWord); /* Copy hbits from old memory into new memory */ memset(hbits, 0, newHBytes); memcpy(hbits, sp->hbits, oldHBytes); PR_DELETE(sp->hbits); memset(sp->base + oldSize, 0, allocSize); /* Adjust segment state */ sp->limit += allocSize; sp->hbits = hbits; sp->info->limit = sp->limit; sp->info->hbits = hbits; /* Put free memory into a freelist bin */ cp = (GCFreeChunk *) (sp->base + oldSize); cp->segment = sp; cp->chunkSize = allocSize; InlineBinNumber(bin, allocSize) cp->next = bins[bin]; bins[bin] = cp; if (bin < minBin) minBin = bin; if (bin > maxBin) maxBin = bin; /* Prevent a pointer that points to the free memory from showing up on the call stack later on */ memset(&cp, 0, sizeof(cp)); /* Update heap brackets and counters */ if ((PRWord*)sp->limit > _pr_gcData.highSeg) { _pr_gcData.highSeg = (PRWord*) sp->limit; } _pr_gcData.allocMemory += allocSize; _pr_gcData.freeMemory += allocSize; return PR_TRUE; } PR_DELETE(hbits); return PR_FALSE;}#endif /* USE_EXTEND_HEAP */static GCSeg *GrowHeapExactly(PRInt32 requestedSize){ GCSeg *sp = DoGrowHeap(requestedSize, PR_TRUE); return sp;}static PRBool GrowHeap(PRInt32 requestedSize){ void *p;#ifdef USE_EXTEND_HEAP if (ExtendHeap(requestedSize)) { return PR_TRUE; }#endif p = DoGrowHeap(requestedSize, PR_FALSE); return (p != NULL ? PR_TRUE : PR_FALSE);}/*** Release a segment when it is entirely free.*/static void ShrinkGCHeap(GCSeg *sp){#ifdef GCMETER if (_pr_gcMeter & _GC_METER_GROWTH) { fprintf(stderr, "[GC: free segment base=%p size=%ld]\n", sp->base, (long) (sp->limit - sp->base)); }#endif /* * Put segment onto free seginfo list (we can't call free right now * because we have the GC lock and all of the other threads are * suspended; if one of them has the malloc lock we would deadlock) */ sp->info->next = freeSegs; freeSegs = sp->info; collectorCleanupNeeded = 1; _pr_gcData.allocMemory -= sp->limit - sp->base; if (sp == lastInHeap) lastInHeap = 0; /* Squish out disappearing segment from segment table */ --nsegs; if ((sp - segs) != nsegs) { *sp = segs[nsegs]; } else { sp->base = 0; sp->limit = 0; sp->hbits = 0; sp->info = 0; } /* Recalculate the lowSeg and highSeg values */ _pr_gcData.lowSeg = (PRWord*) segs[0].base; _pr_gcData.highSeg = (PRWord*) segs[0].limit; for (sp = segs; sp < &segs[nsegs]; sp++) { if ((PRWord*)sp->base < _pr_gcData.lowSeg) { _pr_gcData.lowSeg = (PRWord*) sp->base; } if ((PRWord*)sp->limit > _pr_gcData.highSeg) { _pr_gcData.highSeg = (PRWord*) sp->limit; } }}static void FreeSegments(void){ GCSegInfo *si; while (0 != freeSegs) { LOCK_GC(); si = freeSegs; if (si) { freeSegs = si->next; } UNLOCK_GC(); if (!si) { break; } PR_DELETE(si->base); PR_DELETE(si->hbits); PR_DELETE(si); }}/************************************************************************/void ScanScanQ(GCScanQ *iscan){ PRWord *p; PRWord **pp; PRWord **epp; GCScanQ nextQ, *scan, *next, *temp; CollectorType *ct; if (!iscan->queued) return; _GCTRACE(GC_MARK, ("begin scanQ @ 0x%x (%d)", iscan, iscan->queued)); scan = iscan; next = &nextQ; while (scan->queued) { _GCTRACE(GC_MARK, ("continue scanQ @ 0x%x (%d)", scan, scan->queued)); /* * Set pointer to current scanQ so that _pr_gcData.livePointer * can find it. */ pScanQ = next; next->queued = 0; /* Now scan the scan Q */ pp = scan->q; epp = &scan->q[scan->queued]; scan->queued = 0; while (pp < epp) { p = *pp++; ct = &_pr_collectorTypes[GET_TYPEIX(p[0])]; PR_ASSERT(0 != ct->gctype.scan); /* Scan object ... */ (*ct->gctype.scan)(p + 1); } /* Exchange pointers so that we scan next */ temp = scan; scan = next; next = temp; } pScanQ = iscan; PR_ASSERT(nextQ.queued == 0); PR_ASSERT(iscan->queued == 0);}/*** Called during root finding step to identify "root" pointers into the** GC heap. First validate if it is a real heap pointer and then mark the** object being pointed to and add it to the scan Q for eventual** scanning.*/static void PR_CALLBACK ProcessRootBlock(void **base, PRInt32 count){ GCSeg *sp; PRWord *p0, *p, h, tix, *low, *high, *segBase; CollectorType *ct;#ifdef DEBUG void **base0 = base;#endif low = _pr_gcData.lowSeg; high = _pr_gcData.highSeg; while (--count >= 0) { p0 = (PRWord*) *base++; /* ** 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 < low) continue; /* below gc heap */ if (p0 >= high) continue; /* 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; } } continue; } find_object: /* NOTE: Inline expansion of FindObject */ /* Align p to it's proper boundary before we start fiddling with it */ p = (PRWord*) ((PRWord)p0 & ~(PR_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 winner: h = p[0]; if ((h & MARK_BIT) == 0) {#ifdef DEBUG _GCTRACE(GC_ROOTS, ("root 0x%p (%d) base0=%p off=%d", p, OBJ_BYTES(h), base0, (base-1) - base0));#endif /* Mark the root we just found */ p[0] = h | MARK_BIT; /* * See if object we just found needs scanning. It must * have a scan function to be placed on the scanQ. */ tix = (PRWord)GET_TYPEIX(h); ct = &_pr_collectorTypes[tix]; if (0 == ct->gctype.scan) { continue; } /* ** Put a pointer onto the scan Q. We use the scan Q to avoid ** deep recursion on the C call stack. Objects are added to ** the scan Q until the scan Q fills up. At that point we ** make a call to ScanScanQ which proceeds to scan each of ** the objects in the Q. This limits the recursion level by a ** large amount though the stack frames get larger to hold ** the GCScanQ's. */ pScanQ->q[pScanQ->queued++] = p; if (pScanQ->queued == MAX_SCAN_Q) { METER(_pr_scanDepth++); ScanScanQ(pScanQ); } } }}static void PR_CALLBACK ProcessRootPointer(void *ptr){ PRWord *p0, *p, h, tix, *segBase; GCSeg* sp; CollectorType *ct; 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; /* below gc heap */ if (p0 >= _pr_gcData.highSeg) return; /* 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; } 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 winner: h = p[0]; if ((h & MARK_BIT) == 0) {#ifdef DEBUG _GCTRACE(GC_ROOTS, ("root 0x%p (%d)", p, OBJ_BYTES(h)));#endif /* Mark the root we just found */ p[0] = h | MARK_BIT; /* * See if object we just found needs scanning. It must * have a scan function to be placed on the scanQ. */ tix = (PRWord)GET_TYPEIX(h); ct = &_pr_collectorTypes[tix]; if (0 == ct->gctype.scan) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -