|
|
1.1 ! root 1: /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- ! 2: * ! 3: * The contents of this file are subject to the Netscape Public ! 4: * License Version 1.1 (the "License"); you may not use this file ! 5: * except in compliance with the License. You may obtain a copy of ! 6: * the License at http://www.mozilla.org/NPL/ ! 7: * ! 8: * Software distributed under the License is distributed on an "AS ! 9: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ! 10: * implied. See the License for the specific language governing ! 11: * rights and limitations under the License. ! 12: * ! 13: * The Original Code is Mozilla Communicator client code, released ! 14: * March 31, 1998. ! 15: * ! 16: * The Initial Developer of the Original Code is Netscape ! 17: * Communications Corporation. Portions created by Netscape are ! 18: * Copyright (C) 1998 Netscape Communications Corporation. All ! 19: * Rights Reserved. ! 20: * ! 21: * Contributor(s): ! 22: * ! 23: * Alternatively, the contents of this file may be used under the ! 24: * terms of the GNU Public License (the "GPL"), in which case the ! 25: * provisions of the GPL are applicable instead of those above. ! 26: * If you wish to allow use of your version of this file only ! 27: * under the terms of the GPL and not to allow others to use your ! 28: * version of this file under the NPL, indicate your decision by ! 29: * deleting the provisions above and replace them with the notice ! 30: * and other provisions required by the GPL. If you do not delete ! 31: * the provisions above, a recipient may use your version of this ! 32: * file under either the NPL or the GPL. ! 33: */ ! 34: ! 35: #ifndef jsarena_h___ ! 36: #define jsarena_h___ ! 37: /* ! 38: * Lifetime-based fast allocation, inspired by much prior art, including ! 39: * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" ! 40: * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). ! 41: * ! 42: * Also supports LIFO allocation (JS_ARENA_MARK/JS_ARENA_RELEASE). ! 43: */ ! 44: #include <stdlib.h> ! 45: #include "jstypes.h" ! 46: #include "jscompat.h" ! 47: ! 48: JS_BEGIN_EXTERN_C ! 49: ! 50: typedef struct JSArena JSArena; ! 51: typedef struct JSArenaPool JSArenaPool; ! 52: ! 53: struct JSArena { ! 54: JSArena *next; /* next arena for this lifetime */ ! 55: jsuword base; /* aligned base address, follows this header */ ! 56: jsuword limit; /* one beyond last byte in arena */ ! 57: jsuword avail; /* points to next available byte */ ! 58: }; ! 59: ! 60: #ifdef JS_ARENAMETER ! 61: typedef struct JSArenaStats JSArenaStats; ! 62: ! 63: struct JSArenaStats { ! 64: JSArenaStats *next; /* next in arenaStats list */ ! 65: char *name; /* name for debugging */ ! 66: uint32 narenas; /* number of arenas in pool */ ! 67: uint32 nallocs; /* number of JS_ARENA_ALLOCATE() calls */ ! 68: uint32 nreclaims; /* number of reclaims from freeArenas */ ! 69: uint32 nmallocs; /* number of malloc() calls */ ! 70: uint32 ndeallocs; /* number of lifetime deallocations */ ! 71: uint32 ngrows; /* number of JS_ARENA_GROW() calls */ ! 72: uint32 ninplace; /* number of in-place growths */ ! 73: uint32 nreallocs; /* number of arena grow extending reallocs */ ! 74: uint32 nreleases; /* number of JS_ARENA_RELEASE() calls */ ! 75: uint32 nfastrels; /* number of "fast path" releases */ ! 76: size_t nbytes; /* total bytes allocated */ ! 77: size_t maxalloc; /* maximum allocation size in bytes */ ! 78: double variance; /* size variance accumulator */ ! 79: }; ! 80: #endif ! 81: ! 82: struct JSArenaPool { ! 83: JSArena first; /* first arena in pool list */ ! 84: JSArena *current; /* arena from which to allocate space */ ! 85: size_t arenasize; /* net exact size of a new arena */ ! 86: jsuword mask; /* alignment mask (power-of-2 - 1) */ ! 87: #ifdef JS_ARENAMETER ! 88: JSArenaStats stats; ! 89: #endif ! 90: }; ! 91: ! 92: /* ! 93: * If the including .c file uses only one power-of-2 alignment, it may define ! 94: * JS_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions ! 95: * per ALLOCATE and GROW. ! 96: */ ! 97: #ifdef JS_ARENA_CONST_ALIGN_MASK ! 98: #define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + JS_ARENA_CONST_ALIGN_MASK) \ ! 99: & ~(jsuword)JS_ARENA_CONST_ALIGN_MASK) ! 100: ! 101: #define JS_INIT_ARENA_POOL(pool, name, size) \ ! 102: JS_InitArenaPool(pool, name, size, JS_ARENA_CONST_ALIGN_MASK + 1) ! 103: #else ! 104: #define JS_ARENA_ALIGN(pool, n) (((jsuword)(n) + (pool)->mask) & ~(pool)->mask) ! 105: #endif ! 106: ! 107: #define JS_ARENA_ALLOCATE(p, pool, nb) \ ! 108: JS_ARENA_ALLOCATE_CAST(p, void *, pool, nb) ! 109: ! 110: #define JS_ARENA_ALLOCATE_TYPE(p, type, pool) \ ! 111: JS_ARENA_ALLOCATE_CAST(p, type *, pool, sizeof(type)) ! 112: ! 113: #define JS_ARENA_ALLOCATE_CAST(p, type, pool, nb) \ ! 114: JS_BEGIN_MACRO \ ! 115: JSArena *_a = (pool)->current; \ ! 116: size_t _nb = JS_ARENA_ALIGN(pool, nb); \ ! 117: jsuword _p = _a->avail; \ ! 118: jsuword _q = _p + _nb; \ ! 119: if (_q > _a->limit) \ ! 120: _p = (jsuword)JS_ArenaAllocate(pool, _nb); \ ! 121: else \ ! 122: _a->avail = _q; \ ! 123: p = (type) _p; \ ! 124: JS_ArenaCountAllocation(pool, nb); \ ! 125: JS_END_MACRO ! 126: ! 127: #define JS_ARENA_GROW(p, pool, size, incr) \ ! 128: JS_ARENA_GROW_CAST(p, void *, pool, size, incr) ! 129: ! 130: #define JS_ARENA_GROW_CAST(p, type, pool, size, incr) \ ! 131: JS_BEGIN_MACRO \ ! 132: JSArena *_a = (pool)->current; \ ! 133: if (_a->avail == (jsuword)(p) + JS_ARENA_ALIGN(pool, size)) { \ ! 134: size_t _nb = (size) + (incr); \ ! 135: jsuword _q = (jsuword)(p) + JS_ARENA_ALIGN(pool, _nb); \ ! 136: if (_q <= _a->limit) { \ ! 137: _a->avail = _q; \ ! 138: JS_ArenaCountInplaceGrowth(pool, size, incr); \ ! 139: } else if ((jsuword)(p) == _a->base) { \ ! 140: p = (type) JS_ArenaRealloc(pool, p, size, incr); \ ! 141: } else { \ ! 142: p = (type) JS_ArenaGrow(pool, p, size, incr); \ ! 143: } \ ! 144: } else { \ ! 145: p = (type) JS_ArenaGrow(pool, p, size, incr); \ ! 146: } \ ! 147: JS_ArenaCountGrowth(pool, size, incr); \ ! 148: JS_END_MACRO ! 149: ! 150: #define JS_ARENA_MARK(pool) ((void *) (pool)->current->avail) ! 151: #define JS_UPTRDIFF(p,q) ((jsuword)(p) - (jsuword)(q)) ! 152: ! 153: #ifdef DEBUG ! 154: #define JS_FREE_PATTERN 0xDA ! 155: #define JS_CLEAR_UNUSED(a) (JS_ASSERT((a)->avail <= (a)->limit), \ ! 156: memset((void*)(a)->avail, JS_FREE_PATTERN, \ ! 157: (a)->limit - (a)->avail)) ! 158: #define JS_CLEAR_ARENA(a) memset((void*)(a), JS_FREE_PATTERN, \ ! 159: (a)->limit - (jsuword)(a)) ! 160: #else ! 161: #define JS_CLEAR_UNUSED(a) /* nothing */ ! 162: #define JS_CLEAR_ARENA(a) /* nothing */ ! 163: #endif ! 164: ! 165: #define JS_ARENA_RELEASE(pool, mark) \ ! 166: JS_BEGIN_MACRO \ ! 167: char *_m = (char *)(mark); \ ! 168: JSArena *_a = (pool)->current; \ ! 169: if (_a != &(pool)->first && \ ! 170: JS_UPTRDIFF(_m, _a->base) <= JS_UPTRDIFF(_a->avail, _a->base)) { \ ! 171: _a->avail = (jsuword)JS_ARENA_ALIGN(pool, _m); \ ! 172: JS_ASSERT(_a->avail <= _a->limit); \ ! 173: JS_CLEAR_UNUSED(_a); \ ! 174: JS_ArenaCountRetract(pool, _m); \ ! 175: } else { \ ! 176: JS_ArenaRelease(pool, _m); \ ! 177: } \ ! 178: JS_ArenaCountRelease(pool, _m); \ ! 179: JS_END_MACRO ! 180: ! 181: #ifdef JS_ARENAMETER ! 182: #define JS_COUNT_ARENA(pool,op) ((pool)->stats.narenas op) ! 183: #else ! 184: #define JS_COUNT_ARENA(pool,op) ! 185: #endif ! 186: ! 187: #define JS_ARENA_DESTROY(pool, a, pnext) \ ! 188: JS_BEGIN_MACRO \ ! 189: JS_COUNT_ARENA(pool,--); \ ! 190: if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ ! 191: *(pnext) = (a)->next; \ ! 192: JS_CLEAR_ARENA(a); \ ! 193: free(a); \ ! 194: (a) = NULL; \ ! 195: JS_END_MACRO ! 196: ! 197: /* ! 198: * Initialize an arena pool with the given name for debugging and metering, ! 199: * with a minimum size per arena of size bytes. ! 200: */ ! 201: extern JS_PUBLIC_API(void) ! 202: JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size, ! 203: size_t align); ! 204: ! 205: /* ! 206: * Free the arenas in pool. The user may continue to allocate from pool ! 207: * after calling this function. There is no need to call JS_InitArenaPool() ! 208: * again unless JS_FinishArenaPool(pool) has been called. ! 209: */ ! 210: extern JS_PUBLIC_API(void) ! 211: JS_FreeArenaPool(JSArenaPool *pool); ! 212: ! 213: /* ! 214: * Free the arenas in pool and finish using it altogether. ! 215: */ ! 216: extern JS_PUBLIC_API(void) ! 217: JS_FinishArenaPool(JSArenaPool *pool); ! 218: ! 219: /* ! 220: * Finish using arenas, freeing all memory associated with them except for ! 221: * any locks needed for thread safety. ! 222: */ ! 223: extern JS_PUBLIC_API(void) ! 224: JS_ArenaFinish(void); ! 225: ! 226: /* ! 227: * Free any locks or other memory needed for thread safety, just before ! 228: * shutting down. At that point, we must be called by a single thread. ! 229: * ! 230: * After shutting down, the next thread to call JS_InitArenaPool must not ! 231: * race with any other thread. Once a pool has been initialized, threads ! 232: * may safely call jsarena.c functions on thread-local pools. The upshot ! 233: * is that pools are per-thread, but the underlying global freelist is ! 234: * thread-safe, provided that both the first pool initialization and the ! 235: * shut-down call are single-threaded. ! 236: */ ! 237: extern JS_PUBLIC_API(void) ! 238: JS_ArenaShutDown(void); ! 239: ! 240: /* ! 241: * Friend functions used by the JS_ARENA_*() macros. ! 242: */ ! 243: extern JS_PUBLIC_API(void *) ! 244: JS_ArenaAllocate(JSArenaPool *pool, size_t nb); ! 245: ! 246: extern JS_PUBLIC_API(void *) ! 247: JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr); ! 248: ! 249: extern JS_PUBLIC_API(void *) ! 250: JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr); ! 251: ! 252: extern JS_PUBLIC_API(void) ! 253: JS_ArenaRelease(JSArenaPool *pool, char *mark); ! 254: ! 255: /* ! 256: * Function to be used directly when an allocation has likely grown to consume ! 257: * an entire JSArena, in which case the arena is returned to the malloc heap. ! 258: */ ! 259: extern JS_PUBLIC_API(void) ! 260: JS_ArenaFreeAllocation(JSArenaPool *pool, void *p, size_t size); ! 261: ! 262: #ifdef JS_ARENAMETER ! 263: ! 264: #include <stdio.h> ! 265: ! 266: extern JS_PUBLIC_API(void) ! 267: JS_ArenaCountAllocation(JSArenaPool *pool, size_t nb); ! 268: ! 269: extern JS_PUBLIC_API(void) ! 270: JS_ArenaCountInplaceGrowth(JSArenaPool *pool, size_t size, size_t incr); ! 271: ! 272: extern JS_PUBLIC_API(void) ! 273: JS_ArenaCountGrowth(JSArenaPool *pool, size_t size, size_t incr); ! 274: ! 275: extern JS_PUBLIC_API(void) ! 276: JS_ArenaCountRelease(JSArenaPool *pool, char *mark); ! 277: ! 278: extern JS_PUBLIC_API(void) ! 279: JS_ArenaCountRetract(JSArenaPool *pool, char *mark); ! 280: ! 281: extern JS_PUBLIC_API(void) ! 282: JS_DumpArenaStats(FILE *fp); ! 283: ! 284: #else /* !JS_ARENAMETER */ ! 285: ! 286: #define JS_ArenaCountAllocation(ap, nb) /* nothing */ ! 287: #define JS_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */ ! 288: #define JS_ArenaCountGrowth(ap, size, incr) /* nothing */ ! 289: #define JS_ArenaCountRelease(ap, mark) /* nothing */ ! 290: #define JS_ArenaCountRetract(ap, mark) /* nothing */ ! 291: ! 292: #endif /* !JS_ARENAMETER */ ! 293: ! 294: JS_END_EXTERN_C ! 295: ! 296: #endif /* jsarena_h___ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.