Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions
jsarena.c File Reference
#include "jsstddef.h"
#include <stdlib.h>
#include <string.h>
#include "jstypes.h"
#include "jsbit.h"
#include "jsarena.h"
#include "jsutil.h"

Go to the source code of this file.

Defines

#define COUNT(pool, what)   /* nothing */
#define JS_ARENA_DEFAULT_ALIGN   sizeof(double)
#define POINTER_MASK   ((jsuword)(JS_ALIGN_OF_POINTER - 1))
#define HEADER_SIZE(pool)
#define HEADER_BASE_MASK(pool)   ((pool)->mask | POINTER_MASK)
#define PTR_TO_HEADER(pool, p)
#define GET_HEADER(pool, a)   (*PTR_TO_HEADER(pool, (a)->base))
#define SET_HEADER(pool, a, ap)   (*PTR_TO_HEADER(pool, (a)->base) = (ap))

Functions

 JS_InitArenaPool (JSArenaPool *pool, const char *name, size_t size, size_t align)
 JS_ArenaAllocate (JSArenaPool *pool, size_t nb)
 JS_ArenaRealloc (JSArenaPool *pool, void *p, size_t size, size_t incr)
 JS_ArenaGrow (JSArenaPool *pool, void *p, size_t size, size_t incr)
static void FreeArenaList (JSArenaPool *pool, JSArena *head)
 JS_ArenaRelease (JSArenaPool *pool, char *mark)
 JS_ArenaFreeAllocation (JSArenaPool *pool, void *p, size_t size)
 JS_FreeArenaPool (JSArenaPool *pool)
 JS_FinishArenaPool (JSArenaPool *pool)
 JS_ArenaFinish ()
 JS_ArenaShutDown (void)

Define Documentation

#define COUNT (   pool,
  what 
)    /* nothing */

Definition at line 58 of file jsarena.c.

#define GET_HEADER (   pool,
  a 
)    (*PTR_TO_HEADER(pool, (a)->base))

Definition at line 126 of file jsarena.c.

Definition at line 121 of file jsarena.c.

Value:
(sizeof(JSArena **)                           \
                                 + (((pool)->mask < POINTER_MASK)             \
                                    ? POINTER_MASK - (pool)->mask             \
                                    : 0))

Definition at line 117 of file jsarena.c.

#define JS_ARENA_DEFAULT_ALIGN   sizeof(double)

Definition at line 61 of file jsarena.c.

#define POINTER_MASK   ((jsuword)(JS_ALIGN_OF_POINTER - 1))

Definition at line 116 of file jsarena.c.

#define PTR_TO_HEADER (   pool,
  p 
)
Value:
(JS_ASSERT(((jsuword)(p)                      \
                                            & HEADER_BASE_MASK(pool))         \
                                           == 0),                             \
                                 (JSArena ***)(p) - 1)

Definition at line 122 of file jsarena.c.

#define SET_HEADER (   pool,
  a,
  ap 
)    (*PTR_TO_HEADER(pool, (a)->base) = (ap))

Definition at line 127 of file jsarena.c.


Function Documentation

static void FreeArenaList ( JSArenaPool pool,
JSArena head 
) [static]

Definition at line 272 of file jsarena.c.

{
    JSArena **ap, *a;

    ap = &head->next;
    a = *ap;
    if (!a)
        return;

#ifdef DEBUG
    do {
        JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
        a->avail = a->base;
        JS_CLEAR_UNUSED(a);
    } while ((a = a->next) != NULL);
    a = *ap;
#endif

    do {
        *ap = a->next;
        JS_CLEAR_ARENA(a);
        JS_COUNT_ARENA(pool,--);
        free(a);
    } while ((a = *ap) != NULL);

    pool->current = head;
}

Here is the caller graph for this function:

JS_ArenaAllocate ( JSArenaPool pool,
size_t  nb 
)

Definition at line 130 of file jsarena.c.

{
    JSArena **ap, *a, *b;
    jsuword extra, hdrsz, gross;
    void *p;

    /*
     * Search pool from current forward till we find or make enough space.
     *
     * NB: subtract nb from a->limit in the loop condition, instead of adding
     * nb to a->avail, to avoid overflowing a 32-bit address space (possible
     * when running a 32-bit program on a 64-bit system where the kernel maps
     * the heap up against the top of the 32-bit address space).
     *
     * Thanks to Juergen Kreileder <jk@blackdown.de>, who brought this up in
     * https://bugzilla.mozilla.org/show_bug.cgi?id=279273.
     */
    JS_ASSERT((nb & pool->mask) == 0);
    for (a = pool->current; nb > a->limit || a->avail > a->limit - nb;
         pool->current = a) {
        ap = &a->next;
        if (!*ap) {
            /* Not enough space in pool, so we must malloc. */
            extra = (nb > pool->arenasize) ? HEADER_SIZE(pool) : 0;
            hdrsz = sizeof *a + extra + pool->mask;
            gross = hdrsz + JS_MAX(nb, pool->arenasize);
            if (gross < nb)
                return NULL;
            b = (JSArena *) malloc(gross);
            if (!b)
                return NULL;
            b->next = NULL;
            b->limit = (jsuword)b + gross;
            JS_COUNT_ARENA(pool,++);
            COUNT(pool, nmallocs);

            /* If oversized, store ap in the header, just before a->base. */
            *ap = a = b;
            JS_ASSERT(gross <= JS_UPTRDIFF(a->limit, a));
            if (extra) {
                a->base = a->avail =
                    ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool);
                SET_HEADER(pool, a, ap);
            } else {
                a->base = a->avail = JS_ARENA_ALIGN(pool, a + 1);
            }
            continue;
        }
        a = *ap;                                /* move to next arena */
    }

    p = (void *)a->avail;
    a->avail += nb;
    JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
    return p;
}

Definition at line 410 of file jsarena.c.

{
}
JS_ArenaFreeAllocation ( JSArenaPool pool,
void p,
size_t  size 
)

Definition at line 318 of file jsarena.c.

{
    JSArena **ap, *a, *b;
    jsuword q;

    /*
     * If the allocation is oversized, it consumes an entire arena, and it has
     * a header just before the allocation pointing back to its predecessor's
     * next member.  Otherwise, we have to search pool for a.
     */
    if (size > pool->arenasize) {
        ap = *PTR_TO_HEADER(pool, p);
        a = *ap;
    } else {
        q = (jsuword)p + size;
        q = JS_ARENA_ALIGN(pool, q);
        ap = &pool->first.next;
        while ((a = *ap) != NULL) {
            JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);

            if (a->avail == q) {
                /*
                 * If a is consumed by the allocation at p, we can free it to
                 * the malloc heap.
                 */
                if (a->base == (jsuword)p)
                    break;

                /*
                 * We can't free a, but we can "retract" its avail cursor --
                 * whether there are others after it in pool.
                 */
                a->avail = (jsuword)p;
                return;
            }
            ap = &a->next;
        }
    }

    /*
     * At this point, a is doomed, so ensure that pool->current doesn't point
     * at it.  We must preserve LIFO order of mark/release cursors, so we use
     * the oversized-allocation arena's back pointer (or if not oversized, we
     * use the result of searching the entire pool) to compute the address of
     * the arena that precedes a.
     */
    if (pool->current == a)
        pool->current = (JSArena *) ((char *)ap - offsetof(JSArena, next));

    /*
     * This is a non-LIFO deallocation, so take care to fix up a->next's back
     * pointer in its header, if a->next is oversized.
     */
    *ap = b = a->next;
    if (b && b->avail - b->base > pool->arenasize) {
        JS_ASSERT(GET_HEADER(pool, b) == &a->next);
        SET_HEADER(pool, b, ap);
    }
    JS_CLEAR_ARENA(a);
    JS_COUNT_ARENA(pool,--);
    free(a);
}

Here is the caller graph for this function:

JS_ArenaGrow ( JSArenaPool pool,
void p,
size_t  size,
size_t  incr 
)

Definition at line 250 of file jsarena.c.

{
    void *newp;

    /*
     * If p points to an oversized allocation, it owns an entire arena, so we
     * can simply realloc the arena.
     */
    if (size > pool->arenasize)
        return JS_ArenaRealloc(pool, p, size, incr);

    JS_ARENA_ALLOCATE(newp, pool, size + incr);
    if (newp)
        memcpy(newp, p, size);
    return newp;
}

Here is the call graph for this function:

JS_ArenaRealloc ( JSArenaPool pool,
void p,
size_t  size,
size_t  incr 
)

Definition at line 188 of file jsarena.c.

{
    JSArena **ap, *a, *b;
    jsuword boff, aoff, extra, hdrsz, gross;

    /*
     * Use the oversized-single-allocation header to avoid searching for ap.
     * See JS_ArenaAllocate, the SET_HEADER call.
     */
    if (size > pool->arenasize) {
        ap = *PTR_TO_HEADER(pool, p);
        a = *ap;
    } else {
        ap = &pool->first.next;
        while ((a = *ap) != pool->current)
            ap = &a->next;
    }

    JS_ASSERT(a->base == (jsuword)p);
    boff = JS_UPTRDIFF(a->base, a);
    aoff = JS_ARENA_ALIGN(pool, size + incr);
    JS_ASSERT(aoff > pool->arenasize);
    extra = HEADER_SIZE(pool);                  /* oversized header holds ap */
    hdrsz = sizeof *a + extra + pool->mask;     /* header and alignment slop */
    gross = hdrsz + aoff;
    JS_ASSERT(gross > aoff);
    a = (JSArena *) realloc(a, gross);
    if (!a)
        return NULL;
#ifdef JS_ARENAMETER
    pool->stats.nreallocs++;
#endif

    if (a != *ap) {
        /* Oops, realloc moved the allocation: update other pointers to a. */
        if (pool->current == *ap)
            pool->current = a;
        b = a->next;
        if (b && b->avail - b->base > pool->arenasize) {
            JS_ASSERT(GET_HEADER(pool, b) == &(*ap)->next);
            SET_HEADER(pool, b, &a->next);
        }

        /* Now update *ap, the next link of the arena before a. */
        *ap = a;
    }

    a->base = ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool);
    a->limit = (jsuword)a + gross;
    a->avail = a->base + aoff;
    JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);

    /* Check whether realloc aligned differently, and copy if necessary. */
    if (boff != JS_UPTRDIFF(a->base, a))
        memmove((void *)a->base, (char *)a + boff, size);

    /* Store ap in the oversized-load arena header. */
    SET_HEADER(pool, a, ap);
    return (void *)a->base;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JS_ArenaRelease ( JSArenaPool pool,
char *  mark 
)

Definition at line 301 of file jsarena.c.

{
    JSArena *a;

    for (a = &pool->first; a; a = a->next) {
        JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);

        if (JS_UPTRDIFF(mark, a->base) <= JS_UPTRDIFF(a->avail, a->base)) {
            a->avail = JS_ARENA_ALIGN(pool, mark);
            JS_ASSERT(a->avail <= a->limit);
            FreeArenaList(pool, a);
            return;
        }
    }
}

Here is the call graph for this function:

Definition at line 415 of file jsarena.c.

{
}

Definition at line 389 of file jsarena.c.

{
    FreeArenaList(pool, &pool->first);
#ifdef JS_ARENAMETER
    {
        JSArenaStats *stats, **statsp;

        if (pool->stats.name)
            free(pool->stats.name);
        for (statsp = &arena_stats_list; (stats = *statsp) != 0;
             statsp = &stats->next) {
            if (stats == &pool->stats) {
                *statsp = stats->next;
                return;
            }
        }
    }
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 382 of file jsarena.c.

{
    FreeArenaList(pool, &pool->first);
    COUNT(pool, ndeallocs);
}

Here is the call graph for this function:

Here is the caller graph for this function:

JS_InitArenaPool ( JSArenaPool pool,
const char *  name,
size_t  size,
size_t  align 
)

Definition at line 64 of file jsarena.c.

{
    if (align == 0)
        align = JS_ARENA_DEFAULT_ALIGN;
    pool->mask = JS_BITMASK(JS_CeilingLog2(align));
    pool->first.next = NULL;
    pool->first.base = pool->first.avail = pool->first.limit =
        JS_ARENA_ALIGN(pool, &pool->first + 1);
    pool->current = &pool->first;
    pool->arenasize = size;
#ifdef JS_ARENAMETER
    memset(&pool->stats, 0, sizeof pool->stats);
    pool->stats.name = strdup(name);
    pool->stats.next = arena_stats_list;
    arena_stats_list = &pool->stats;
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function: