Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Functions | Variables
prmsgc.c File Reference
#include <string.h>
#include <stddef.h>
#include <stdarg.h>
#include <time.h>
#include "prclist.h"
#include "prbit.h"
#include "prtypes.h"
#include "prenv.h"
#include "prgc.h"
#include "prthread.h"
#include "prlog.h"
#include "prlong.h"
#include "prinrval.h"
#include "prprf.h"
#include "gcint.h"
#include "private/pprthred.h"

Go to the source code of this file.

Classes

struct  GCFreeChunk
struct  GCSegInfo
struct  GCSeg
struct  GCScanQStr
struct  GCBlockEnd
struct  GCFinalStr
struct  GCWeakStr

Defines

#define METER(x)
#define MAX_SCAN_Q   100L
#define MAX_SEGS   400L
#define MAX_SEGMENT_SIZE   (2L * 256L * 1024L)
#define SEGMENT_SIZE   (1L * 256L * 1024L)
#define MAX_ALLOC_SIZE   (4L * 1024L * 1024L)
#define MAX_INT   ((1UL << (PR_BITS_PER_INT - 1)) - 1)
#define MAX_ALLOC   ( (1L << (PR_BYTES_PER_WORD_LOG2 + WORDS_BITS )) -1)
#define MIN_FREE_THRESHOLD_AFTER_GC   20L
#define LINEAR_BIN_EXPONENT   5
#define NUM_LINEAR_BINS   ((PRUint32)1 << LINEAR_BIN_EXPONENT)
#define FIRST_LOG_BIN   (NUM_LINEAR_BINS - LINEAR_BIN_EXPONENT)
#define NUM_BINS   (FIRST_LOG_BIN + 32)
#define InlineBinNumber(_bin, _bytes)
#define BIG_ALLOC   16384L
#define MIN_FREE_CHUNK_BYTES   ((PRInt32)sizeof(GCFreeChunk))
#define BIG_ALLOC_GC_SIZE   (4*SEGMENT_SIZE)
#define TYPEIX_BITS   8L
#define WORDS_BITS   20L
#define MAX_CBS   (1L << GC_TYPEIX_BITS)
#define MAX_WORDS   (1L << GC_WORDS_BITS)
#define TYPEIX_SHIFT   24L
#define MAX_TYPEIX   ((1L << TYPEIX_BITS) - 1L)
#define TYPEIX_MASK   PR_BITMASK(TYPEIX_BITS)
#define WORDS_SHIFT   2L
#define WORDS_MASK   PR_BITMASK(WORDS_BITS)
#define MARK_BIT   1L
#define FINAL_BIT   2L
#define GC_USER_BITS_SHIFT   22L
#define GC_USER_BITS   0x00c00000L
#define MAKE_HEADER(_cbix, _words)
#define GET_TYPEIX(_h)   (((PRUword)(_h) >> TYPEIX_SHIFT) & 0xff)
#define MARK(_sp, _p)   (((PRWord *)(_p))[0] |= MARK_BIT)
#define IS_MARKED(_sp, _p)   (((PRWord *)(_p))[0] & MARK_BIT)
#define OBJ_BYTES(_h)   (((PRInt32) (_h) & 0x003ffffcL) << (PR_BYTES_PER_WORD_LOG2-2L))
#define GC_GET_USER_BITS(_h)   (((_h) & GC_USER_BITS) >> GC_USER_BITS_SHIFT)
#define SET_HBIT(_sp, _ph)   SET_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base)))
#define CLEAR_HBIT(_sp, _ph)   CLEAR_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base)))
#define IS_HBIT(_sp, _ph)   TEST_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base)))
#define OutputDebugString(msg)
#define IN_SEGMENT(_sp, _p)
#define PR_BLOCK_END   0xDEADBEEF
#define FinalPtr(_qp)   ((GCFinal*) ((char*) (_qp) - offsetof(GCFinal,links)))
#define WeakPtr(_qp)   ((GCWeak*) ((char*) (_qp) - offsetof(GCWeak,links)))
#define WEAK_FREELIST_ISEMPTY()   (_pr_freeWeakLinks.next == &_pr_freeWeakLinks)

Typedefs

typedef void(* PRFileDumper )(FILE *out, PRBool detailed)
typedef struct GCFreeChunk GCFreeChunk
typedef struct GCSegInfo GCSegInfo
typedef struct GCSeg GCSeg
typedef struct GCScanQStr GCScanQ
typedef struct GCBlockEnd GCBlockEnd
typedef struct GCFinalStr GCFinal
typedef struct GCWeakStr GCWeak
typedef void(* WalkObject_t )(FILE *out, GCType *tp, PRWord *obj, size_t bytes, PRBool detailed)
typedef void(* WalkUnknown_t )(FILE *out, GCType *tp, PRWord tix, PRWord *p, size_t bytes, PRBool detailed)
typedef void(* WalkFree_t )(FILE *out, PRWord *p, size_t size, PRBool detailed)
typedef void(* WalkSegment_t )(FILE *out, GCSeg *sp, PRBool detailed)

Functions

 PR_DumpToFile (char *filename, char *msg, PRFileDumper dump, PRBool detailed)
 Added by Vishy for sanity checking a few GC structures.
static PRWordFindObject (GCSeg *sp, PRWord *p)
static GCSegInHeap (void *p)
static GCSegDoGrowHeap (PRInt32 requestedSize, PRBool exactly)
static GCSegGrowHeapExactly (PRInt32 requestedSize)
static PRBool GrowHeap (PRInt32 requestedSize)
static void ShrinkGCHeap (GCSeg *sp)
static void FreeSegments (void)
void ScanScanQ (GCScanQ *iscan)
static void PR_CALLBACK ProcessRootBlock (void **base, PRInt32 count)
static void PR_CALLBACK ProcessRootPointer (void *ptr)
static void EmptyFreelists (void)
static PRBool SweepSegment (GCSeg *sp)
static GCFinalAllocFinalNode (void)
static void FreeFinalNode (GCFinal *node)
static void PrepareFinalize (void)
void PR_CALLBACK _PR_ScanFinalQueue (void *notused)
void PR_CALLBACK FinalizerLoop (void *unused)
static void NotifyFinalizer (void)
void _PR_CreateFinalizer (PRThreadScope scope)
void pr_FinalizeOnExit (void)
 PR_IMPLEMENT (void)
static void PR_CALLBACK ScanWeakFreeList (void *notused)
static void EmptyWeakFreeList (void)
static GCWeakAllocWeakNode (void)
static void FreeWeakNode (GCWeak *node)
static void CheckWeakLinks (void)
static void dogc (void)
static PRInt32 PR_CALLBACK pr_ConservativeWalkPointer (void *ptr, PRWalkFun walkRootPointer, void *data)
static PRInt32 PR_CALLBACK pr_ConservativeWalkBlock (void **base, PRInt32 count, PRWalkFun walkRootPointer, void *data)
static void pr_WalkSegment (FILE *out, GCSeg *sp, PRBool detailed, char *enterMsg, char *exitMsg, WalkObject_t walkObject, WalkUnknown_t walkUnknown, WalkFree_t walkFree)
static void pr_WalkSegments (FILE *out, WalkSegment_t walkSegment, PRBool detailed)
 PR_DumpIndent (FILE *out, int indent)
static void PR_DumpHexWords (FILE *out, PRWord *p, int nWords, int indent, int nWordsPerLine)
static void PR_CALLBACK pr_DumpObject (FILE *out, GCType *tp, PRWord *p, size_t bytes, PRBool detailed)
static void PR_CALLBACK pr_DumpUnknown (FILE *out, GCType *tp, PRWord tix, PRWord *p, size_t bytes, PRBool detailed)
static void PR_CALLBACK pr_DumpFree (FILE *out, PRWord *p, size_t size, PRBool detailed)
static void PR_CALLBACK pr_DumpSegment (FILE *out, GCSeg *sp, PRBool detailed)
static void pr_DumpRoots (FILE *out)
 PR_DumpGCHeap (FILE *out, PRBool detailed)
 PR_DumpMemory (PRBool detailed)
static PRInt32 PR_CALLBACK pr_DumpRootPointer (PRWord *p, void *data)
static void PR_CALLBACK pr_ConservativeDumpRootPointer (void *ptr)
static void PR_CALLBACK pr_ConservativeDumpRootBlock (void **base, PRInt32 count)
int DumpThreadRoots (PRThread *t, int i, void *notused)
 PR_RegisterSummaryPrinter (PRSummaryPrinter fun, void *closure)
static void PR_CALLBACK pr_SummarizeObject (FILE *out, GCType *tp, PRWord *p, size_t bytes, PRBool detailed)
static void PR_CALLBACK pr_DumpSummary (FILE *out, GCSeg *sp, PRBool detailed)
 PR_DumpGCSummary (FILE *out, PRBool detailed)
 PR_DumpMemorySummary (void)
static PRWordBinAlloc (int cbix, PRInt32 bytes, int dub)
static PRWordBigAlloc (int cbix, PRInt32 bytes, int dub)
static void CollectorCleanup (void)
 PR_IMPLEMENT (PRWord GCPTR *)
 PR_AllocSimpleMemory (PRWord requestedBytes, PRInt32 tix)
 PR_IMPLEMENT (PRWord)

Variables

PRLogModuleInfo_pr_msgc_lm
PRLogModuleInfoGC
static PRInt32 _pr_pageShift
static PRInt32 _pr_pageSize
static PRInt32 segmentSize = SEGMENT_SIZE
static PRInt32 collectorCleanupNeeded
static GCSeg segs [MAX_SEGS]
static GCSegInfofreeSegs
static GCSeglastInHeap
static int nsegs
static GCFreeChunkbins [NUM_BINS]
static PRInt32 minBin
static PRInt32 maxBin
static GCScanQpScanQ
static PRWord bigAllocBytes = 0
PRCList _pr_finalizeableObjects
PRCList _pr_finalQueue
PRCList _pr_weakLinks = PR_INIT_STATIC_CLIST(&_pr_weakLinks)
PRCList _pr_freeWeakLinks = PR_INIT_STATIC_CLIST(&_pr_freeWeakLinks)
GCLockHook_pr_GCLockHook
PRSummaryPrinter summaryPrinter = NULL
voidsummaryPrinterClosure = NULL
static PRBool allocationEnabled = PR_TRUE

Class Documentation

struct GCFreeChunk

Definition at line 186 of file prmsgc.c.

Collaboration diagram for GCFreeChunk:
Class Members
PRInt32 chunkSize
struct GCFreeChunk * next
struct GCSeg * segment
struct GCSegInfo

Definition at line 192 of file prmsgc.c.

Collaboration diagram for GCSegInfo:
Class Members
char * base
int fromMalloc
PRWord * hbits
char * limit
struct GCSegInfo * next
struct GCSeg

Definition at line 200 of file prmsgc.c.

Collaboration diagram for GCSeg:
Class Members
char * base
PRWord * hbits
GCSegInfo * info
char * limit
struct GCScanQStr

Definition at line 233 of file prmsgc.c.

Collaboration diagram for GCScanQStr:
Class Members
PRWord * q
int queued
struct GCBlockEnd

Definition at line 1025 of file prmsgc.c.

Class Members
PRInt32 check
struct GCFinalStr

Definition at line 1285 of file prmsgc.c.

Class Members
PRCList links
PRWord * object
struct GCWeakStr

Definition at line 1500 of file prmsgc.c.

Class Members
PRCList links
PRWord * object

Define Documentation

#define BIG_ALLOC   16384L

Definition at line 180 of file prmsgc.c.

Definition at line 251 of file prmsgc.c.

#define CLEAR_HBIT (   _sp,
  _ph 
)    CLEAR_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base)))

Definition at line 304 of file prmsgc.c.

#define FINAL_BIT   2L

Definition at line 269 of file prmsgc.c.

#define FinalPtr (   _qp)    ((GCFinal*) ((char*) (_qp) - offsetof(GCFinal,links)))

Definition at line 1291 of file prmsgc.c.

Definition at line 155 of file prmsgc.c.

#define GC_GET_USER_BITS (   _h)    (((_h) & GC_USER_BITS) >> GC_USER_BITS_SHIFT)

Definition at line 290 of file prmsgc.c.

#define GC_USER_BITS   0x00c00000L

Definition at line 274 of file prmsgc.c.

Definition at line 273 of file prmsgc.c.

#define GET_TYPEIX (   _h)    (((PRUword)(_h) >> TYPEIX_SHIFT) & 0xff)

Definition at line 280 of file prmsgc.c.

#define IN_SEGMENT (   _sp,
  _p 
)
Value:
((((char *)(_p)) >= (_sp)->base) &&    \
     (((char *)(_p)) < (_sp)->limit))

Definition at line 408 of file prmsgc.c.

#define InlineBinNumber (   _bin,
  _bytes 
)
Value:
{  \
    PRUint32 _t, _n = (PRUint32) _bytes / 4;  \
    if (_n < NUM_LINEAR_BINS) {  \
        _bin = _n;  \
    } else {  \
        _bin = FIRST_LOG_BIN;  \
        if ((_t = (_n >> 16)) != 0) { _bin += 16; _n = _t; }  \
        if ((_t = (_n >> 8)) != 0)  { _bin += 8; _n = _t; }  \
        if ((_t = (_n >> 4)) != 0)  { _bin += 4; _n = _t; }  \
        if ((_t = (_n >> 2)) != 0) { _bin += 2; _n = _t; }  \
        if ((_n >> 1) != 0) _bin++;  \
    }  \
}

Definition at line 165 of file prmsgc.c.

#define IS_HBIT (   _sp,
  _ph 
)    TEST_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base)))

Definition at line 307 of file prmsgc.c.

#define IS_MARKED (   _sp,
  _p 
)    (((PRWord *)(_p))[0] & MARK_BIT)

Definition at line 285 of file prmsgc.c.

Definition at line 153 of file prmsgc.c.

#define MAKE_HEADER (   _cbix,
  _words 
)
Value:
((PRWord) (((unsigned long)(_cbix) << TYPEIX_SHIFT) \
         | ((unsigned long)(_words) << WORDS_SHIFT)))

Definition at line 276 of file prmsgc.c.

#define MARK (   _sp,
  _p 
)    (((PRWord *)(_p))[0] |= MARK_BIT)

Definition at line 283 of file prmsgc.c.

#define MARK_BIT   1L

Definition at line 268 of file prmsgc.c.

#define MAX_ALLOC   ( (1L << (PR_BYTES_PER_WORD_LOG2 + WORDS_BITS )) -1)

Definition at line 128 of file prmsgc.c.

#define MAX_ALLOC_SIZE   (4L * 1024L * 1024L)

Definition at line 112 of file prmsgc.c.

#define MAX_CBS   (1L << GC_TYPEIX_BITS)

Definition at line 261 of file prmsgc.c.

#define MAX_INT   ((1UL << (PR_BITS_PER_INT - 1)) - 1)

Definition at line 120 of file prmsgc.c.

#define MAX_SCAN_Q   100L

Definition at line 101 of file prmsgc.c.

#define MAX_SEGMENT_SIZE   (2L * 256L * 1024L)

Definition at line 110 of file prmsgc.c.

#define MAX_SEGS   400L

Definition at line 109 of file prmsgc.c.

#define MAX_TYPEIX   ((1L << TYPEIX_BITS) - 1L)

Definition at line 264 of file prmsgc.c.

#define MAX_WORDS   (1L << GC_WORDS_BITS)

Definition at line 262 of file prmsgc.c.

#define METER (   x)

Definition at line 94 of file prmsgc.c.

Definition at line 182 of file prmsgc.c.

Definition at line 136 of file prmsgc.c.

Definition at line 159 of file prmsgc.c.

Definition at line 154 of file prmsgc.c.

#define OBJ_BYTES (   _h)    (((PRInt32) (_h) & 0x003ffffcL) << (PR_BYTES_PER_WORD_LOG2-2L))

Definition at line 287 of file prmsgc.c.

Definition at line 404 of file prmsgc.c.

#define PR_BLOCK_END   0xDEADBEEF

Definition at line 1039 of file prmsgc.c.

#define SEGMENT_SIZE   (1L * 256L * 1024L)

Definition at line 111 of file prmsgc.c.

#define SET_HBIT (   _sp,
  _ph 
)    SET_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base)))

Definition at line 301 of file prmsgc.c.

#define TYPEIX_BITS   8L

Definition at line 259 of file prmsgc.c.

Definition at line 265 of file prmsgc.c.

#define TYPEIX_SHIFT   24L

Definition at line 263 of file prmsgc.c.

Definition at line 1514 of file prmsgc.c.

#define WeakPtr (   _qp)    ((GCWeak*) ((char*) (_qp) - offsetof(GCWeak,links)))

Definition at line 1508 of file prmsgc.c.

#define WORDS_BITS   20L

Definition at line 260 of file prmsgc.c.

Definition at line 267 of file prmsgc.c.

#define WORDS_SHIFT   2L

Definition at line 266 of file prmsgc.c.


Typedef Documentation

typedef struct GCBlockEnd GCBlockEnd
typedef struct GCFinalStr GCFinal
typedef struct GCFreeChunk GCFreeChunk
typedef struct GCScanQStr GCScanQ
typedef struct GCSeg GCSeg
typedef struct GCSegInfo GCSegInfo
typedef struct GCWeakStr GCWeak

Definition at line 67 of file prmsgc.c.

typedef void(* WalkFree_t)(FILE *out, PRWord *p, size_t size, PRBool detailed)

Definition at line 1935 of file prmsgc.c.

typedef void(* WalkObject_t)(FILE *out, GCType *tp, PRWord *obj, size_t bytes, PRBool detailed)

Definition at line 1931 of file prmsgc.c.

Definition at line 1936 of file prmsgc.c.

typedef void(* WalkUnknown_t)(FILE *out, GCType *tp, PRWord tix, PRWord *p, size_t bytes, PRBool detailed)

Definition at line 1933 of file prmsgc.c.


Function Documentation

Definition at line 1457 of file prmsgc.c.

{
    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();

    }
}

Here is the call graph for this function:

Definition at line 1385 of file prmsgc.c.

{
#ifdef XP_MAC
#pragma unused (notused)
#endif
    PRCList *qp;
    GCFinal *fp;
    PRWord *p;
    void ( PR_CALLBACK *livePointer)(void *ptr);

    livePointer = _pr_gcData.livePointer;
    qp = _pr_finalQueue.next;
    while (qp != &_pr_finalQueue) {
    fp = FinalPtr(qp);
       _GCTRACE(GC_FINAL, ("marking 0x%x (on final queue)", fp->object));
        p = &fp->object[1];
    (*livePointer)(p);
    qp = qp->next;
    }
}

Here is the caller graph for this function:

static GCFinal* AllocFinalNode ( void  ) [static]

Definition at line 1294 of file prmsgc.c.

{
    return PR_NEWZAP(GCFinal);
}

Here is the caller graph for this function:

static GCWeak* AllocWeakNode ( void  ) [static]

Definition at line 1571 of file prmsgc.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static PRWord* BigAlloc ( int  cbix,
PRInt32  bytes,
int  dub 
) [static]

Definition at line 2601 of file prmsgc.c.

{
    GCSeg *sp;
    PRWord *p, h;
    PRInt32 chunkSize;

    /*
    ** If the number of bytes allocated via BigAlloc() since the last GC
    ** exceeds BIG_ALLOC_GC_SIZE then do a GC Now...
    */
    if (bigAllocBytes >= BIG_ALLOC_GC_SIZE) {
        dogc();
    }
    bigAllocBytes += bytes;

    /* Get a segment to hold this allocation */
    sp = GrowHeapExactly(bytes);

    if (sp) {
        p = (PRWord*) sp->base;
        chunkSize = sp->limit - sp->base;

        /* All memory is double aligned on 64 bit machines... */
#ifndef IS_64
        if (dub && (((PRWord)p & (PR_BYTES_PER_DWORD-1)) == 0)) {
            /*
            ** Consume the first word of the chunk with a dummy
            ** unreferenced object.
            */
            p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, 1);
            SET_HBIT(sp, p);
            p++;
            chunkSize -= PR_BYTES_PER_WORD;
            _pr_gcData.freeMemory -= PR_BYTES_PER_WORD;
            _pr_gcData.busyMemory += PR_BYTES_PER_WORD;
            PR_ASSERT(((PRWord)p & (PR_BYTES_PER_DWORD-1)) != 0);
        }
#endif

#if defined(WIN16)
            /* All memory MUST be aligned on 32bit boundaries */
            PR_ASSERT( (((PRWord)p) & (PR_BYTES_PER_WORD-1)) == 0 );
#endif

        /* Consume the *entire* segment with a single allocation */
        h = MAKE_HEADER(cbix, (chunkSize >> PR_BYTES_PER_WORD_LOG2));
        p[0] = h;
        SET_HBIT(sp, p);
        _pr_gcData.freeMemory -= chunkSize;
        _pr_gcData.busyMemory += chunkSize;
    return p;
    }
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRWord* BinAlloc ( int  cbix,
PRInt32  bytes,
int  dub 
) [static]

Definition at line 2510 of file prmsgc.c.

{
    GCFreeChunk **cpp, *cp, *cpNext;
    GCSeg *sp;
    PRInt32 chunkSize, remainder;
    PRWord *p, *np;
    PRInt32 bin, newbin;

    /* Compute bin that allocation belongs in */
    InlineBinNumber(bin,bytes)
    if (bin < minBin) {
    bin = minBin;    /* Start at first filled bin */
    }

    /* Search in the bin, and larger bins, for a big enough piece */
    for (; bin <= NUM_BINS-1; bin++) {
        cpp = &bins[bin];
    while ((cp = *cpp) != 0) {
        chunkSize = cp->chunkSize;
        if (chunkSize < bytes) {
        /* Too small; skip it */
            METER(meter.skippedFreeChunks++);
        cpp = &cp->next;
        continue;
        }

        /* We have found a hunk of memory large enough to use */
        p = (PRWord*) cp;
        sp = cp->segment;
        cpNext = cp->next;
#ifndef IS_64
        if (dub && (((PRWord)p & (PR_BYTES_PER_DWORD-1)) == 0)) {
        /*
         * We are double aligning the memory and the current free
         * chunk is aligned on an even boundary. Because header
         * words are one word long we need to discard the first
         * word of memory.
         */
        p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, 1);
        SET_HBIT(sp, p);
        p++;
        chunkSize -= PR_BYTES_PER_WORD;
        bytes -= PR_BYTES_PER_WORD;
        PR_ASSERT(((PRWord)p & (PR_BYTES_PER_DWORD-1)) != 0);
        _pr_gcData.freeMemory -= PR_BYTES_PER_WORD;
        _pr_gcData.busyMemory += PR_BYTES_PER_WORD;
        }
#endif
        np = (PRWord*) ((char*) p + bytes);
        remainder = chunkSize - bytes;
        if (remainder >= MIN_FREE_CHUNK_BYTES) {
        /* The left over memory is large enough to be freed. */
        cp = (GCFreeChunk*) np;
        cp->segment = sp;
        cp->chunkSize = remainder;
        InlineBinNumber(newbin, remainder)
        if (newbin != bin) {
            *cpp = (GCFreeChunk*) cpNext; /* remove */
            cp->next = bins[newbin];      /* insert */
            bins[newbin] = cp;
            if (newbin < minBin) minBin = newbin;
            if (newbin > maxBin) maxBin = newbin;
        } else {
            /* Leave it on the same list */
            cp->next = cpNext;
            *cpp = (GCFreeChunk*) np;
        }
        } else {
        /*
         * The left over memory is too small to be released. Just
         * leave it attached to the chunk of memory being
         * returned.
         */
        *cpp = cpNext;
        bytes = chunkSize;
        }
        p[0] = MAKE_HEADER(cbix, (bytes >> PR_BYTES_PER_WORD_LOG2));
        SET_HBIT(sp, p);
        _pr_gcData.freeMemory -= bytes;
        _pr_gcData.busyMemory += bytes;
        return p;
    }
    }
    return 0;
}

Here is the caller graph for this function:

static void CheckWeakLinks ( void  ) [static]

Definition at line 1588 of file prmsgc.c.

                                 {
    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;
        }
    }
    }
}

Here is the caller graph for this function:

static void CollectorCleanup ( void  ) [static]

Definition at line 2664 of file prmsgc.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void dogc ( void  ) [static]

Definition at line 1650 of file prmsgc.c.

{
    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
}

Here is the call graph for this function:

Here is the caller graph for this function:

static GCSeg* DoGrowHeap ( PRInt32  requestedSize,
PRBool  exactly 
) [static]

Definition at line 440 of file prmsgc.c.

{
    GCSeg *sp;
    GCSegInfo *segInfo;
    GCFreeChunk *cp;
    char *base;
    PRWord *hbits;
    PRInt32 nhbytes, nhbits;
    PRUint32 allocSize;

    if (nsegs == MAX_SEGS) {
    /* No room for more segments */
    return 0;
    }

    segInfo = (GCSegInfo*) PR_MALLOC(sizeof(GCSegInfo));
#ifdef DEBUG
    {
    char str[256];
    sprintf(str, "[1] Allocated %ld bytes at %p\n",
        (long) sizeof(GCSegInfo), segInfo);
    OutputDebugString(str);
    }
#endif
    if (!segInfo) {
    return 0;
    }

#if defined(WIN16)
    if (requestedSize > segmentSize) {
    PR_DELETE(segInfo);
    return 0;
    }
#endif

    /* Get more memory from the OS */
    if (exactly) {
    allocSize = requestedSize;
    base = (char *) PR_MALLOC(requestedSize);
    } else {
    allocSize = requestedSize;
    allocSize = (allocSize + _pr_pageSize - 1L) >> _pr_pageShift;
    allocSize <<= _pr_pageShift;
    base = (char*)_MD_GrowGCHeap(&allocSize);
    }
    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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int DumpThreadRoots ( PRThread t,
int  i,
void notused 
)
static void EmptyFreelists ( void  ) [static]

Definition at line 994 of file prmsgc.c.

{
    GCFreeChunk *cp;
    GCFreeChunk *next;
    GCSeg *sp;
    PRWord *p;
    PRInt32 chunkSize;
    PRInt32 bin;

    /*
    ** Run over the freelist and make all of the free chunks look like
    ** object debris.
    */
    for (bin = 0; bin <= NUM_BINS-1; bin++) {
        cp = bins[bin];
        while (cp) {
            next = cp->next;
            sp = cp->segment;
            chunkSize = cp->chunkSize >> BYTES_PER_WORD_LOG2;
            p = (PRWord*) cp;
            PR_ASSERT(chunkSize != 0);
            p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, chunkSize);
            SET_HBIT(sp, p);
            cp = next;
        }
        bins[bin] = 0;
    }
    minBin = NUM_BINS - 1;
    maxBin = 0;
}

Here is the caller graph for this function:

static void EmptyWeakFreeList ( void  ) [static]

Definition at line 1538 of file prmsgc.c.

                                    {
    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);
    }
    }
}

Here is the caller graph for this function:

Definition at line 1406 of file prmsgc.c.

{
#ifdef XP_MAC
#pragma unused (unused)
#endif
    GCFinal *fp;
    PRWord *p;
    PRWord h, tix;
    CollectorType *ct;

    LOCK_GC();
    for (;;) {
       p = 0; h = 0;        /* don't let the gc find these pointers */
    while (PR_CLIST_IS_EMPTY(&_pr_finalQueue))
        PR_Wait(_pr_gcData.lock, PR_INTERVAL_NO_TIMEOUT);

    _GCTRACE(GC_FINAL, ("begin finalization"));
    while (_pr_finalQueue.next != &_pr_finalQueue) {
        fp = FinalPtr(_pr_finalQueue.next);
        PR_REMOVE_LINK(&fp->links);
        p = fp->object;

        h = p[0];        /* Grab header word */
        tix = (PRWord)GET_TYPEIX(h);
        ct = &_pr_collectorTypes[tix];
           _GCTRACE(GC_FINAL, ("finalize 0x%x (%d)", p, OBJ_BYTES(h)));

        /*
        ** Give up the GC lock so that other threads can allocate memory
        ** while this finalization method is running. Get it back
        ** afterwards so that the list remains thread safe.
        */
        UNLOCK_GC();
        FreeFinalNode(fp);
        PR_ASSERT(ct->gctype.finalize != 0);
        (*ct->gctype.finalize)(p + 1);
        LOCK_GC();
    }
    _GCTRACE(GC_FINAL, ("end finalization"));
    PR_Notify(_pr_gcData.lock);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRWord* FindObject ( GCSeg sp,
PRWord p 
) [static]

Definition at line 378 of file prmsgc.c.

{
    PRWord *base;
    
    /* Align p to it's proper boundary before we start fiddling with it */
    p = (PRWord*) ((PRWord)p & ~(PR_BYTES_PER_WORD-1L));

    base = (PRWord *) sp->base;
#if defined(WIN16)
    PR_ASSERT( SELECTOROF(p) == SELECTOROF(base));
#endif
    do {
    if (IS_HBIT(sp, p)) {
        return (p);
    }
    p--;
    } while ( p >= base );

    /* Heap is corrupted! */
    _GCTRACE(GC_TRACE, ("ERROR: The heap is corrupted!!! aborting now!"));
    abort();
    return NULL;
}

Here is the caller graph for this function:

static void FreeFinalNode ( GCFinal node) [static]

Definition at line 1299 of file prmsgc.c.

{
    PR_DELETE(node);
}

Here is the caller graph for this function:

static void FreeSegments ( void  ) [static]

Definition at line 717 of file prmsgc.c.

{
    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);
    }
}

Here is the caller graph for this function:

static void FreeWeakNode ( GCWeak node) [static]

Definition at line 1577 of file prmsgc.c.

{
    PR_DELETE(node);
}

Here is the caller graph for this function:

static PRBool GrowHeap ( PRInt32  requestedSize) [static]

Definition at line 658 of file prmsgc.c.

{
  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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static GCSeg* GrowHeapExactly ( PRInt32  requestedSize) [static]

Definition at line 652 of file prmsgc.c.

{
    GCSeg *sp = DoGrowHeap(requestedSize, PR_TRUE);
    return sp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static GCSeg* InHeap ( void p) [static]

Definition at line 417 of file prmsgc.c.

{
    GCSeg *sp, *esp;

    if (lastInHeap && IN_SEGMENT(lastInHeap, p)) {
    return lastInHeap;
    }

    sp = segs;
    esp = segs + nsegs;
    for (; sp < esp; sp++) {
    if (IN_SEGMENT(sp, p)) {
        lastInHeap = sp;
        return sp;
    }
    }
    return 0;
}

Here is the caller graph for this function:

static void NotifyFinalizer ( void  ) [static]

Definition at line 1449 of file prmsgc.c.

Here is the call graph for this function:

Here is the caller graph for this function:

PR_AllocSimpleMemory ( PRWord  requestedBytes,
PRInt32  tix 
)

Definition at line 3034 of file prmsgc.c.

{
    PRWord *p;
    PRInt32 bytes;
    PRInt32 objBytes;
#ifdef GC_STATS
    PRInt64 allocTime, ldelta;
#endif

    if (!allocationEnabled) return NULL;

    PR_ASSERT(requestedBytes >= 0);
    PR_ASSERT(_pr_collectorTypes[tix].flags != 0);

#ifdef DEBUG
    if (_pr_do_a_dump) {
       /*
       ** Collect, pause for a second (lets finalizer run), and then GC
       ** again.
       */
       PR_GC();
       PR_Sleep(PR_MicrosecondsToInterval(1000000L));
       PR_GC();
       PR_DumpGCHeap(_pr_dump_file, PR_TRUE);
       _pr_do_a_dump = 0;
    }
#endif

#ifdef GC_STATS
    allocTime = PR_NowMS();
#endif
    bytes = (PRInt32) requestedBytes;

    /*
    ** Align bytes to a multiple of a PRWord, then add in enough space
    ** to hold the header word.
    **
    ** MSVC 1.52 crashed on the ff. code because of the "complex" shifting :-(
    */
#if !defined(WIN16) 
    bytes = (bytes + PR_BYTES_PER_WORD - 1) >> PR_BYTES_PER_WORD_LOG2;
    bytes <<= PR_BYTES_PER_WORD_LOG2;
    bytes += sizeof(PRWord);
#else 
    /* 
    ** For WIN16 the shifts have been broken out into separate statements
    ** to prevent the compiler from crashing...
    */
    {
    PRWord shiftVal;

    bytes += PR_BYTES_PER_WORD - 1L;
    shiftVal = PR_BYTES_PER_WORD_LOG2;
    bytes >>= shiftVal;
    bytes <<= shiftVal;
    bytes += sizeof(PRWord);
    }
#endif
    
    /*
     * Add in an extra word of memory for double-aligned memory. Some
     * percentage of the time this will waste a word of memory (too
     * bad). Howver, it makes the allocation logic much simpler and
     * faster.
     */
#ifndef IS_64
    bytes += PR_BYTES_PER_WORD;
#endif

#ifdef GC_CHECK
    if (_pr_gcData.flags & GC_CHECK) {
    /* Bloat the allocation a bit so that we can lay down
       a check pattern that we will validate */
    bytes += PR_BYTES_PER_WORD * 2;
    }
#endif

#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS)
    bytes += sizeof(GCBlockEnd);
#endif

#if defined(WIN16)
    PR_ASSERT( bytes < MAX_ALLOC_SIZE );
#endif
    /* Java can ask for objects bigger than 4M, but it won't get them */
    /*
     * This check was added because there is a fundamental limit of
     * the size field maintained by the gc code.  Going over the 4M
     * limit caused some bits to roll over into another bit field,
     * violating the max segment size and causing a bug.
     */
    if (bytes >= MAX_ALLOC_SIZE) {
        return NULL;
    }
#ifdef DEBUG
    if (gc_thrash == -1L
       ? (gc_thrash = (long)PR_GetEnv("GC_THRASH"))
       : gc_thrash) {
       PR_GC();
    }
#endif

    LOCK_GC();
#ifdef GC_CHECK
    if (_pr_gcData.flags & GC_CHECK) {
    CheckHeap();
    }
    allocationCount++;
#endif

    /* Try default allocation */
    if ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) {
    p = BigAlloc(tix, bytes, 1);
    } else {
    p = BinAlloc(tix, bytes, 1);
    }
    if (0 == p) {
#ifdef GC_STATS
      LL_SUB(ldelta, PR_Now(), allocTime);
#endif
      /* Collect some memory */
      _GCTRACE(GC_ALLOC, ("force GC: want %d", bytes));
      dogc();
      PR_ASSERT( GC_IS_LOCKED() );

      /* After a collection we check and see if we should grow the
     heap. We grow the heap when the amount of memory free is less
     than a certain percentage of the heap size. We don't check to
     see if the grow succeeded because our fallback strategy in
     either case is to try one more time to allocate. */
      if ((_pr_gcData.allocMemory < _pr_gcData.maxMemory) &&
      (_pr_gcData.freeMemory <
       ((_pr_gcData.allocMemory * MIN_FREE_THRESHOLD_AFTER_GC) / 100L))) {
    GrowHeap(PR_MAX(bytes, segmentSize));
      }
#ifdef GC_STATS
      LL_ADD(allocTime, PR_Now(), ldelta);
#endif

      /* Try one last time */
      if ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) {
    p = BigAlloc(tix, bytes, 1);
      } else {
    p = BinAlloc(tix, bytes, 1);
      }
      if (0 == p) {
    /* Well that lost big time. Memory must be pretty well fragmented */
    if (!GrowHeap(PR_MAX(bytes, segmentSize))) {
      goto lost;
    }
    p = BinAlloc(tix, bytes, 1);
    if (0 == p) goto lost;
      }
    }

    /* Zero out the portion of the object memory that was used by
       the GCFreeChunk structure (skip the first word because it
       was already overwritten by the gc header word) */
    objBytes = OBJ_BYTES(p[0]);
    if (objBytes > sizeof(PRWord)) p[1] = 0;
    if (objBytes > sizeof(PRWord)*2) p[2] = 0;

    METER(meter.allocBytes += bytes);
    METER(meter.wastedBytes += (bytes - requestedBytes));
    UNLOCK_GC();

    if (collectorCleanupNeeded) {
       CollectorCleanup();
    }

#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS)
    {
       GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
       end->check = PR_BLOCK_END;
    }
#endif
#ifdef GC_STATS
    {
       PRInt64 now = PR_Now();
       double delta;
       PRInt32 bin;
       GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));

       end->allocTime = allocTime;
       LL_SUB(ldelta, now, allocTime);
       LL_L2D(delta, ldelta);
       InlineBinNumber(bin, requestedBytes);
       end->bin = bin;
       gcstats[bin].nallocs++;
       gcstats[bin].allocTime += delta;
       gcstats[bin].allocTimeVariance += delta * delta;
    }
#endif
#ifdef GC_CHECK
    if (_pr_gcData.flags & GC_CHECK) {
    /* Place a pattern in the memory that was allocated that was not
       requested. We will check the pattern later. */
    char* cp = (char*)(p + 1) + requestedBytes;
       GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
       char i = (char) 0xff;
       while (cp < (char*)end) {
           *cp++ = i--;
       }
       end->requestedBytes = requestedBytes;
       CheckHeap();
    }
#endif
    return p + 1;

  lost:
    /* Out of memory */
    UNLOCK_GC();
    if (collectorCleanupNeeded) {
    CollectorCleanup();
    }
    return 0;
}

Here is the call graph for this function:

static void PR_CALLBACK pr_ConservativeDumpRootBlock ( void **  base,
PRInt32  count 
) [static]

Definition at line 2133 of file prmsgc.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2127 of file prmsgc.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 PR_CALLBACK pr_ConservativeWalkBlock ( void **  base,
PRInt32  count,
PRWalkFun  walkRootPointer,
void data 
) [static]

Definition at line 1916 of file prmsgc.c.

{
    PRWord *p0;
    while (--count >= 0) {
       PRInt32 status;
        p0 = (PRWord*) *base++;
       status = pr_ConservativeWalkPointer(p0, walkRootPointer, data);
       if (status) return status;
    }
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 PR_CALLBACK pr_ConservativeWalkPointer ( void ptr,
PRWalkFun  walkRootPointer,
void data 
) [static]

Definition at line 1854 of file prmsgc.c.

{
  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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_CALLBACK pr_DumpFree ( FILE out,
PRWord p,
size_t  size,
PRBool  detailed 
) [static]

Definition at line 2057 of file prmsgc.c.

{
#if defined(XP_MAC) && XP_MAC
# pragma unused( detailed )
#endif

    fprintf(out, "0x%p: 0x%.6lX -  FREE\n", p, (long) size);
}

Here is the call graph for this function:

Here is the caller graph for this function:

PR_DumpGCHeap ( FILE out,
PRBool  detailed 
)

Definition at line 2081 of file prmsgc.c.

{
    fprintf(out, "\n"
        "The kinds are:\n"
        " U unscanned block\n"
        " W weak link block\n"
        " S scanned block\n"
        " F scanned and final block\n"
        " C class record\n"
        " X context record\n"
        " - free list item\n"
        " ? other\n");
    LOCK_GC();
    pr_WalkSegments(out, pr_DumpSegment, detailed);
    if (detailed)
    pr_DumpRoots(out);
    UNLOCK_GC();
}

Here is the call graph for this function:

Here is the caller graph for this function:

PR_DumpGCSummary ( FILE out,
PRBool  detailed 
)

Definition at line 2213 of file prmsgc.c.

{
    if (summaryPrinter) {
    pr_WalkSegments(out, pr_DumpSummary, detailed);
    summaryPrinter(out, summaryPrinterClosure);
    }
#if 0
    fprintf(out, "\nFinalizable objects:\n");
    {
    PRCList *qp;
    qp = _pr_pendingFinalQueue.next;
    while (qp != &_pr_pendingFinalQueue) {
        GCFinal* fp = FinalPtr(qp);
        PRWord h = fp->object[0];        /* Grab header word */
        PRWord tix = GET_TYPEIX(h);
        GCType* tp = _pr_gcTypes[tix];
        size_t bytes = OBJ_BYTES(h);
        pr_DumpObject(out, tp, fp->object, bytes, PR_FALSE);
        qp = qp->next;
    }
    }
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_DumpHexWords ( FILE out,
PRWord p,
int  nWords,
int  indent,
int  nWordsPerLine 
) [static]

Definition at line 2009 of file prmsgc.c.

{
    while (nWords > 0)
    {
    int i;

    PR_DumpIndent(out, indent);
    i = nWordsPerLine;
    if (i > nWords)
        i = nWords;
    nWords -= i;
    while (i--)
    {
        fprintf(out, "0x%.8lX", (long) *p++);
        if (i)
        fputc(' ', out);
    }
    fputc('\n', out);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

PR_DumpIndent ( FILE out,
int  indent 
)

Definition at line 2002 of file prmsgc.c.

{
    while (--indent >= 0)
    fprintf(out, " ");
}

Here is the call graph for this function:

Here is the caller graph for this function:

PR_DumpMemory ( PRBool  detailed)

Definition at line 2101 of file prmsgc.c.

{
    PR_DumpToFile("memory.out", "Dumping memory", PR_DumpGCHeap, detailed);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2238 of file prmsgc.c.

{
    PR_DumpToFile("memory.out", "Memory Summary", PR_DumpGCSummary, PR_FALSE);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_CALLBACK pr_DumpObject ( FILE out,
GCType tp,
PRWord p,
size_t  bytes,
PRBool  detailed 
) [static]

Definition at line 2032 of file prmsgc.c.

{
    char kindChar = tp->kindChar;
    fprintf(out, "0x%p: 0x%.6lX %c  ",
            p, (long) bytes, kindChar ? kindChar : '?');
    if (tp->dump)
    (*tp->dump)(out, (void*) (p + 1), detailed, 0);
    if (detailed)
    PR_DumpHexWords(out, p, bytes>>2, 22, 4);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 PR_CALLBACK pr_DumpRootPointer ( PRWord p,
void data 
) [static]

Definition at line 2109 of file prmsgc.c.

{
#ifdef XP_MAC
#pragma unused(data)
#endif
    PRWord h = p[0];
    PRWord tix = GET_TYPEIX(h);
      size_t bytes = OBJ_BYTES(h);
      
      GCType* tp = &_pr_collectorTypes[tix].gctype;
      if (0 != tp)
      pr_DumpObject(_pr_gcData.dumpOutput, tp, p, bytes, PR_FALSE);
      else
      pr_DumpUnknown(_pr_gcData.dumpOutput, tp, tix, p, bytes, PR_FALSE);
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void pr_DumpRoots ( FILE out) [static]

Definition at line 2142 of file prmsgc.c.

{
    RootFinder *rf;
    void (*liveBlock)(void **base, PRInt32 count);
    void (*livePointer)(void *ptr);
    void (*processRootBlock)(void **base, PRInt32 count);
    void (*processRootPointer)(void *ptr);

    LOCK_GC();

    liveBlock = _pr_gcData.liveBlock;
    livePointer = _pr_gcData.livePointer;
    processRootBlock = _pr_gcData.processRootBlock;
    processRootPointer = _pr_gcData.processRootPointer;
    
    _pr_gcData.liveBlock = pr_ConservativeDumpRootBlock;
    _pr_gcData.livePointer = pr_ConservativeDumpRootPointer;
    _pr_gcData.processRootBlock = pr_ConservativeDumpRootBlock;
    _pr_gcData.processRootPointer = pr_ConservativeDumpRootPointer;
    _pr_gcData.dumpOutput = out;

    rf = _pr_rootFinders;
    while (rf) {
    fprintf(out, "\n===== Roots for %s\n", rf->name);
    (*rf->func)(rf->arg);
    rf = rf->next;
    }

    _pr_gcData.liveBlock = liveBlock;
    _pr_gcData.livePointer = livePointer;
    _pr_gcData.processRootBlock = processRootBlock;
    _pr_gcData.processRootPointer = processRootPointer;
    _pr_gcData.dumpOutput = NULL;

    UNLOCK_GC();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_CALLBACK pr_DumpSegment ( FILE out,
GCSeg sp,
PRBool  detailed 
) [static]

Definition at line 2067 of file prmsgc.c.

{
    pr_WalkSegment(out, sp, detailed,
           "\n   Address: Length\n0x%p: Beginning of segment\n",
           "0x%p: End of segment\n\n",
           pr_DumpObject, pr_DumpUnknown, pr_DumpFree);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_CALLBACK pr_DumpSummary ( FILE out,
GCSeg sp,
PRBool  detailed 
) [static]

Definition at line 2206 of file prmsgc.c.

Here is the call graph for this function:

Here is the caller graph for this function:

PR_DumpToFile ( char *  filename,
char *  msg,
PRFileDumper  dump,
PRBool  detailed 
)

Added by Vishy for sanity checking a few GC structures.

Can use SanityCheckGC to debug corrupted GC Heap situations

Definition at line 3484 of file prmsgc.c.

{
    FILE *out;
    OutputDebugString(msg);
    out = fopen(filename, "a");
    if (!out) {
       char buf[64];
       PR_ASSERT(strlen(filename) < sizeof(buf) - 16);
       PR_snprintf(buf, sizeof(buf), "Can't open \"%s\"\n",
                  filename);
       OutputDebugString(buf);
    }
    else
    {
       struct tm *newtime;
       time_t aclock;
       int i;

       time(&aclock);
       newtime = localtime(&aclock);
       fprintf(out, "%s on %s\n", msg, asctime(newtime));  /* Print current time */
       dump(out, detailed);
       fprintf(out, "\n\n");
       for (i = 0; i < 80; i++)
           fprintf(out, "=");
       fprintf(out, "\n\n");
       fclose(out);
    }
    OutputDebugString(" done\n");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_CALLBACK pr_DumpUnknown ( FILE out,
GCType tp,
PRWord  tix,
PRWord p,
size_t  bytes,
PRBool  detailed 
) [static]

Definition at line 2045 of file prmsgc.c.

{
    char kindChar = tp->kindChar;
    fprintf(out, "0x%p: 0x%.6lX %c  ",
            p, (long) bytes, kindChar ? kindChar : '?');
    fprintf(out, "UNKNOWN KIND %ld\n", (long) tix);
    if (detailed)
    PR_DumpHexWords(out, p, bytes>>2, 22, 4);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1472 of file prmsgc.c.

{
#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
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1485 of file prmsgc.c.

{
    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) */
}

Here is the call graph for this function:

Definition at line 2761 of file prmsgc.c.

{
    PRWord *p;
    CollectorType *ct;
    PRInt32 bytes;
    GCFinal *final = 0;
    GCWeak *weak = 0;
    int dub = flags & PR_ALLOC_DOUBLE;
    PRInt32 objBytes;
#ifdef GC_STATS
    PRInt64 allocTime, ldelta;
#endif

    if (!allocationEnabled) return NULL;

    PR_ASSERT(requestedBytes >= 0);
    PR_ASSERT(_pr_collectorTypes[tix].flags != 0);

#ifdef DEBUG
    if (_pr_do_a_dump) {
    /*
    ** Collect, pause for a second (lets finalizer run), and then GC
    ** again.
    */
    PR_GC();
    PR_Sleep(PR_MicrosecondsToInterval(1000000L));
    PR_GC();
    PR_DumpGCHeap(_pr_dump_file, PR_TRUE);
    _pr_do_a_dump = 0;
    }
#endif

#ifdef GC_STATS
    allocTime = PR_Now();
#endif
    bytes = (PRInt32) requestedBytes;

    /*
    ** Align bytes to a multiple of a PRWord, then add in enough space
    ** to hold the header word.
    **
    ** MSVC 1.52 crashed on the ff. code because of the "complex" shifting :-(
    */
#if !defined(WIN16) 
    /* Check for possible overflow of bytes before performing add */
    if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL;
    bytes = (bytes + PR_BYTES_PER_WORD - 1) >> PR_BYTES_PER_WORD_LOG2;
    bytes <<= PR_BYTES_PER_WORD_LOG2;
    /* Check for possible overflow of bytes before performing add */
    if ((MAX_INT - sizeof(PRWord)) < bytes ) return NULL;
    bytes += sizeof(PRWord);
#else 
    /* 
    ** For WIN16 the shifts have been broken out into separate statements
    ** to prevent the compiler from crashing...
    */
    {
        PRWord shiftVal;

        /* Check for possible overflow of bytes before performing add */
        if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL;
        bytes += PR_BYTES_PER_WORD - 1L;
        shiftVal = PR_BYTES_PER_WORD_LOG2;
        bytes >>= shiftVal;
        bytes <<= shiftVal;
        /* Check for possible overflow of bytes before performing add */
        if ((MAX_INT - sizeof(PRWord)) < bytes ) return NULL;
        bytes += sizeof(PRWord);
    }
#endif
    /*
     * Add in an extra word of memory for double-aligned memory. Some
     * percentage of the time this will waste a word of memory (too
     * bad). Howver, it makes the allocation logic much simpler and
     * faster.
     */
#ifndef IS_64
    if (dub) {
        /* Check for possible overflow of bytes before performing add */
        if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL;
        bytes += PR_BYTES_PER_WORD;
    }
#endif

#ifdef GC_CHECK
    if (_pr_gcData.flags & GC_CHECK) {
        /* Bloat the allocation a bit so that we can lay down
           a check pattern that we will validate */
        /* Check for possible overflow of bytes before performing add */
        if ((MAX_INT - PR_BYTES_PER_WORD * 3) < bytes ) return NULL;
        bytes += PR_BYTES_PER_WORD * 3;
    }
#endif

#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS)
    if ((MAX_INT - sizeof(GCBlockEnd)) < bytes ) return NULL;
    bytes += sizeof(GCBlockEnd);
#endif

    PR_ASSERT( bytes < MAX_ALLOC_SIZE );
    /*
    ** Java can ask for objects bigger than MAX_ALLOC_SIZE,
    ** but it won't get them.
    */
    if (bytes >= MAX_ALLOC_SIZE) return NULL;

#ifdef DEBUG
    if (gc_thrash == -1L ? (gc_thrash = (long)PR_GetEnv("GC_THRASH")):gc_thrash) PR_GC();
#endif

    ct = &_pr_collectorTypes[tix];
    if (ct->flags & (_GC_TYPE_FINAL|_GC_TYPE_WEAK)) {
    if (0 != ct->gctype.finalize) {
        /*
        ** Allocate a GCFinal struct for this object in advance. Don't put
        ** it on the pending list until we have allocated the object
        */
        final = AllocFinalNode();
        if (!final) {
        /* XXX THIS IS NOT ACCEPTABLE*/
              PR_ASSERT(0);
        return 0;
        }
    }
    if (0 != ct->gctype.getWeakLinkOffset) {
        /*
        ** Allocate a GCWeak struct for this object in advance. Don't put
        ** it on the weak links list until we have allocated the object
        */
        weak = AllocWeakNode();
        if (!weak) {
        /* XXX THIS IS NOT ACCEPTABLE*/
        if (0 != final) {
            FreeFinalNode(final);
        }
              PR_ASSERT(0);
        return 0;
        }
    }
    }

    LOCK_GC();
#ifdef GC_CHECK
    if (_pr_gcData.flags & GC_CHECK) CheckHeap();
    allocationCount++;
#endif

    /* Check for overflow of maximum size we can handle */
    if (bytes > MAX_ALLOC) goto lost;

    /* Try default allocation */
    p = ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) ?
        BigAlloc(tix, bytes, dub) : BinAlloc(tix, bytes, dub);
    if (0 == p) {
#ifdef GC_STATS
        LL_SUB(ldelta, PR_Now(), allocTime);
#endif
        /* Collect some memory */
        _GCTRACE(GC_ALLOC, ("force GC: want %d", bytes));
        dogc();
        PR_ASSERT( GC_IS_LOCKED() );

        /* After a collection we check and see if we should grow the
        ** heap. We grow the heap when the amount of memory free is less
        ** than a certain percentage of the heap size. We don't check to
        ** see if the grow succeeded because our fallback strategy in
        ** either case is to try one more time to allocate. */
        if ((_pr_gcData.allocMemory < _pr_gcData.maxMemory)
        && ((_pr_gcData.freeMemory <
            ((_pr_gcData.allocMemory * MIN_FREE_THRESHOLD_AFTER_GC) / 100L))
        || (_pr_gcData.freeMemory < bytes))) {
            GrowHeap(PR_MAX(bytes, segmentSize));
        }
#ifdef GC_STATS
        LL_ADD(allocTime, PR_Now(), ldelta);
#endif

        /* Try again */
        p = ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) ?
            BigAlloc(tix, bytes, dub) : BinAlloc(tix, bytes, dub);
        if (0 == p) {
            /* Well that lost big time. Memory must be pretty well fragmented */
            if (!GrowHeap(PR_MAX(bytes, segmentSize))) goto lost;
            p = BinAlloc(tix, bytes, dub);
            if (0 == p) goto lost;
        }
    }

    /* Zero out the portion of the object memory that was used by
       the GCFreeChunk structure (skip the first word because it
       was already overwritten by the gc header word) */
    objBytes = OBJ_BYTES(p[0]);
    if (objBytes > sizeof(PRWord)) p[1] = 0;
    if (objBytes > sizeof(PRWord)*2) p[2] = 0;

    if (final) {
       _GCTRACE(GC_ALLOC, ("alloc 0x%x (%d) final=0x%x",
                p, bytes, final));
    final->object = p;
    PR_APPEND_LINK(&final->links, &_pr_finalizeableObjects);
    } else {
       _GCTRACE(GC_ALLOC, ("alloc 0x%x (%d)", p, bytes));
    }
    if (weak) {
    weak->object = p;
    PR_APPEND_LINK(&weak->links, &_pr_weakLinks);
    }
    METER(meter.allocBytes += bytes);
    METER(meter.wastedBytes += (bytes - requestedBytes));
    UNLOCK_GC();

    if (collectorCleanupNeeded) {
       CollectorCleanup();
    }

#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS)
    {
       GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
       end->check = PR_BLOCK_END;
    }
#endif
#ifdef GC_STATS
    {
       PRInt64 now = PR_Now();
       double delta;
       PRInt32 bin;
       GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));

       end->allocTime = allocTime;
       LL_SUB(ldelta, now, allocTime);
       LL_L2D(delta, ldelta);
       InlineBinNumber(bin, requestedBytes);
       end->bin = bin;
       gcstats[bin].nallocs++;
       gcstats[bin].allocTime += delta;
       gcstats[bin].allocTimeVariance += delta * delta;
    }
#endif
#ifdef GC_CHECK
    if (_pr_gcData.flags & GC_CHECK) {
    /* Place a pattern in the memory that was allocated that was not
       requested. We will check the pattern later. */
    char* cp = (char*)(p + 1) + requestedBytes;
       GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd));
       char i = (char) 0xff;
       while (cp < (char*)end) {
           *cp++ = i--;
       }
       end->requestedBytes = requestedBytes;
       CheckHeap();
    }
#endif
    return p + 1;

  lost:
    /* Out of memory */
    UNLOCK_GC();
    if (final) {
    FreeFinalNode(final);
    }
    if (weak) {
    FreeWeakNode(weak);
    }
    if (collectorCleanupNeeded) {
    CollectorCleanup();
    }
    return 0;
}

Here is the call graph for this function:

Definition at line 3254 of file prmsgc.c.

                                                   {
    GCSeg *sp;
    PRWord *h;

    if (ptr == 0) return 0;
    sp = InHeap(ptr);
    if (sp == 0) return 0;
    h = (PRWord*)FindObject(sp, (PRWord*)ptr);
    return GC_GET_USER_BITS(h[0]);
}

Here is the call graph for this function:

Definition at line 2187 of file prmsgc.c.

static void PR_CALLBACK pr_SummarizeObject ( FILE out,
GCType tp,
PRWord p,
size_t  bytes,
PRBool  detailed 
) [static]

Definition at line 2194 of file prmsgc.c.

{
#if defined(XP_MAC) && XP_MAC
# pragma unused( out, detailed )
#endif

    if (tp->summarize)
    (*tp->summarize)((void GCPTR*)(p + 1), bytes);
}

Here is the caller graph for this function:

static void pr_WalkSegment ( FILE out,
GCSeg sp,
PRBool  detailed,
char *  enterMsg,
char *  exitMsg,
WalkObject_t  walkObject,
WalkUnknown_t  walkUnknown,
WalkFree_t  walkFree 
) [static]

Definition at line 1939 of file prmsgc.c.

{
    PRWord *p, *limit;

    p = (PRWord *) sp->base;
    limit = (PRWord *) sp->limit;
    if (enterMsg)
    fprintf(out, enterMsg, p);
    while (p < limit)
    {
    if (IS_HBIT(sp, p)) /* Is this an object header? */
    {
        PRWord h = p[0];
        PRWord tix = GET_TYPEIX(h);
        size_t bytes = OBJ_BYTES(h);
        PRWord* np = (PRWord*) ((char*)p + bytes);

        GCType* tp = &_pr_collectorTypes[tix].gctype;
        if ((0 != tp) && walkObject)
        walkObject(out, tp, p, bytes, detailed);
        else if (walkUnknown)
        walkUnknown(out, tp, tix, p, bytes, detailed);
        p = np;
    }
    else
    {
        /* Must be a freelist item */
        size_t size = ((GCFreeChunk*)p)->chunkSize;
        if (walkFree)
        walkFree(out, p, size, detailed);
        p = (PRWord*)((char*)p + size);
    }
    }
    if (p != limit)
    fprintf(out, "SEGMENT OVERRUN (end should be at 0x%p)\n", limit);
    if (exitMsg)
    fprintf(out, exitMsg, p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void pr_WalkSegments ( FILE out,
WalkSegment_t  walkSegment,
PRBool  detailed 
) [static]

Definition at line 1981 of file prmsgc.c.

{
    GCSeg *sp = segs;
    GCSeg *esp;

    LOCK_GC();
    esp = sp + nsegs;
    while (sp < esp)
    {
    walkSegment(out, sp, detailed);
    sp++;
    }
    fprintf(out, "End of heap\n");
    UNLOCK_GC();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PrepareFinalize ( void  ) [static]

Definition at line 1316 of file prmsgc.c.

{
    PRCList *qp;
    GCFinal *fp;
    PRWord h;
    PRWord *p;
    void (PR_CALLBACK *livePointer)(void *ptr);
#ifdef DEBUG
    CollectorType *ct;
#endif

    /* This must be done under the same lock that the finalizer uses */
    PR_ASSERT( GC_IS_LOCKED() );

    /* cache this ptr */
    livePointer = _pr_gcData.livePointer;

    /*
     * Pass #1: Identify objects that are to be finalized, set their
     * FINAL_BIT.
     */
    qp = _pr_finalizeableObjects.next;
    while (qp != &_pr_finalizeableObjects) {
    fp = FinalPtr(qp);
    qp = qp->next;
    h = fp->object[0];        /* Grab header word */
    if (h & MARK_BIT) {
        /* Object is already alive */
        continue;
    }

#ifdef DEBUG
    ct = &_pr_collectorTypes[GET_TYPEIX(h)];
    PR_ASSERT((0 != ct->flags) && (0 != ct->gctype.finalize));
#endif
    fp->object[0] |= FINAL_BIT;
    _GCTRACE(GC_FINAL, ("moving %p (%d) to finalQueue",
               fp->object, OBJ_BYTES(h)));
    }

    /*
     * Pass #2: For each object that is going to be finalized, move it to
     * the finalization queue and resurrect it
     */
    qp = _pr_finalizeableObjects.next;
    while (qp != &_pr_finalizeableObjects) {
    fp = FinalPtr(qp);
    qp = qp->next;
    h = fp->object[0];        /* Grab header word */
    if ((h & FINAL_BIT) == 0) {
        continue;
    }

    /* Resurrect the object and any objects it refers to */
        p = &fp->object[1];
    (*livePointer)(p);
    PR_REMOVE_LINK(&fp->links);
    PR_APPEND_LINK(&fp->links, &_pr_finalQueue);
    }
}

Here is the caller graph for this function:

static void PR_CALLBACK ProcessRootBlock ( void **  base,
PRInt32  count 
) [static]

Definition at line 791 of file prmsgc.c.

{
    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);
            }
        }
    }
}

Here is the call graph for this function:

static void PR_CALLBACK ProcessRootPointer ( void ptr) [static]

Definition at line 892 of file prmsgc.c.

{
  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) {
      return;
    }

    /*
    ** 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);
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void ScanScanQ ( GCScanQ iscan)

Definition at line 740 of file prmsgc.c.

{
    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);
}

Here is the caller graph for this function:

static void PR_CALLBACK ScanWeakFreeList ( void notused) [static]

Definition at line 1520 of file prmsgc.c.

                                                        {
#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);
    }
}

Here is the call graph for this function:

static void ShrinkGCHeap ( GCSeg sp) [static]

Definition at line 673 of file prmsgc.c.

{
#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;
    }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool SweepSegment ( GCSeg sp) [static]

Definition at line 1142 of file prmsgc.c.

{
    PRWord h, tix;
    PRWord *p;
    PRWord *np;
    PRWord *limit;
    GCFreeChunk *cp;
    PRInt32 bytes, chunkSize, segmentSize, totalFree;
    CollectorType *ct;
    PRInt32 bin;

    /*
    ** Now scan over the segment's memory in memory order, coallescing
    ** all of the debris into a FreeChunk list.
    */
    totalFree = 0;
    segmentSize = sp->limit - sp->base;
    p = (PRWord *) sp->base;
    limit = (PRWord *) sp->limit;
    PR_ASSERT(segmentSize > 0);
    while (p < limit) {
    chunkSize = 0;
    cp = (GCFreeChunk *) p;

    /* Attempt to coallesce any neighboring free objects */
    for (;;) {
        PR_ASSERT(IS_HBIT(sp, p) != 0);
        h = p[0];
        bytes = OBJ_BYTES(h);
        PR_ASSERT(bytes != 0);
        np = (PRWord *) ((char *)p + bytes);
        tix = (PRWord)GET_TYPEIX(h);
        if ((h & MARK_BIT) && (tix != FREE_MEMORY_TYPEIX)) {
#ifdef DEBUG
        if (tix != FREE_MEMORY_TYPEIX) {
            PR_ASSERT(_pr_collectorTypes[tix].flags != 0);
        }
#endif
        p[0] = h & ~(MARK_BIT|FINAL_BIT);
              _GCTRACE(GC_SWEEP, ("busy 0x%x (%d)", p, bytes));
              break;
           }
           _GCTRACE(GC_SWEEP, ("free 0x%x (%d)", p, bytes));

           /* Found a free object */
#ifdef GC_STATS
           {
              PRInt32 userSize = bytes - sizeof(GCBlockEnd);
              GCBlockEnd* end = (GCBlockEnd*)((char*)p + userSize);
              if (userSize >= 0 && end->check == PR_BLOCK_END) {
                  PRInt64 now = PR_Now();
                  double nowd, delta;
                  PRInt32 freq;
                  LL_L2D(nowd, now);
                  delta = nowd - end->allocTime;
                  gcstats[end->bin].nfrees++;
                  gcstats[end->bin].lifetime += delta;
                  gcstats[end->bin].lifetimeVariance += delta * delta;

                  InlineBinNumber(freq, delta);
                  gcltfreq[end->bin][freq]++;

                  end->check = 0;
              }
           }
#endif
        CLEAR_HBIT(sp, p);
        ct = &_pr_collectorTypes[tix];
        if (0 != ct->gctype.free) {
                (*ct->gctype.free)(p + 1);
            }
        chunkSize = chunkSize + bytes;
        if (np == limit) {
        /* Found the end of heap */
        break;
        }
        PR_ASSERT(np < limit);
        p = np;
    }

    if (chunkSize) {
        _GCTRACE(GC_SWEEP, ("free chunk 0x%p to 0x%p (%d)",
                   cp, (char*)cp + chunkSize - 1, chunkSize));
        if (chunkSize < MIN_FREE_CHUNK_BYTES) {
        /* Lost a tiny fragment until (maybe) next time */
                METER(meter.wastedBytes += chunkSize);
        p = (PRWord *) cp;
        chunkSize >>= BYTES_PER_WORD_LOG2;
        PR_ASSERT(chunkSize != 0);
        p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, chunkSize);
        SET_HBIT(sp, p);
        } else {
                /* See if the chunk constitutes the entire segment */
                if (chunkSize == segmentSize) {
                    /* Free up the segment right now */
            if (sp->info->fromMalloc) {
                    ShrinkGCHeap(sp);
                    return PR_TRUE;
                }
                }

                /* Put free chunk into the appropriate bin */
                cp->segment = sp;
        cp->chunkSize = chunkSize;
                InlineBinNumber(bin, chunkSize)
                cp->next = bins[bin];
                bins[bin] = cp;
        if (bin < minBin) minBin = bin;
        if (bin > maxBin) maxBin = bin;

        /* Zero swept memory now */
        memset(cp+1, 0, chunkSize - sizeof(*cp));
                METER(meter.numFreeChunks++);
        totalFree += chunkSize;
        }
    }

    /* Advance to next object */
    p = np;
    }

    PR_ASSERT(totalFree <= segmentSize);

    _pr_gcData.freeMemory += totalFree;
    _pr_gcData.busyMemory += (sp->limit - sp->base) - totalFree;
    return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 1275 of file prmsgc.c.

PRCList _pr_finalQueue

Definition at line 1279 of file prmsgc.c.

Definition at line 1512 of file prmsgc.c.

Definition at line 76 of file prgcapi.c.

Definition at line 78 of file prmsgc.c.

Definition at line 81 of file prmsgc.c.

Definition at line 82 of file prmsgc.c.

Definition at line 1511 of file prmsgc.c.

Definition at line 2657 of file prmsgc.c.

PRWord bigAllocBytes = 0 [static]

Definition at line 252 of file prmsgc.c.

Definition at line 225 of file prmsgc.c.

Definition at line 141 of file prmsgc.c.

GCSegInfo* freeSegs [static]

Definition at line 221 of file prmsgc.c.

Definition at line 79 of file prmsgc.c.

GCSeg* lastInHeap [static]

Definition at line 222 of file prmsgc.c.

PRInt32 maxBin [static]

Definition at line 227 of file prmsgc.c.

PRInt32 minBin [static]

Definition at line 226 of file prmsgc.c.

int nsegs [static]

Definition at line 223 of file prmsgc.c.

GCScanQ* pScanQ [static]

Definition at line 238 of file prmsgc.c.

Definition at line 139 of file prmsgc.c.

GCSeg segs[MAX_SEGS] [static]

Definition at line 220 of file prmsgc.c.

Definition at line 2183 of file prmsgc.c.

Definition at line 2184 of file prmsgc.c.