]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | /* | |
3 | * The contents of this file are subject to the Mozilla 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/MPL/ | |
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 the Netscape Portable Runtime (NSPR). | |
14 | * | |
15 | * The Initial Developer of the Original Code is Netscape | |
16 | * Communications Corporation. Portions created by Netscape are | |
17 | * Copyright (C) 1998-2000 Netscape Communications Corporation. All | |
18 | * Rights Reserved. | |
19 | * | |
20 | * Contributor(s): | |
21 | * | |
22 | * Alternatively, the contents of this file may be used under the | |
23 | * terms of the GNU General Public License Version 2 or later (the | |
24 | * "GPL"), in which case the provisions of the GPL are applicable | |
25 | * instead of those above. If you wish to allow use of your | |
26 | * version of this file only under the terms of the GPL and not to | |
27 | * allow others to use your version of this file under the MPL, | |
28 | * indicate your decision by deleting the provisions above and | |
29 | * replace them with the notice and other provisions required by | |
30 | * the GPL. If you do not delete the provisions above, a recipient | |
31 | * may use your version of this file under either the MPL or the | |
32 | * GPL. | |
33 | */ | |
34 | ||
35 | #ifndef plarena_h___ | |
36 | #define plarena_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 (PL_ARENA_MARK/PL_ARENA_RELEASE). | |
43 | */ | |
44 | #include "prtypes.h" | |
45 | #include "plarenas.h" | |
46 | ||
47 | PR_BEGIN_EXTERN_C | |
48 | ||
49 | typedef struct PLArena PLArena; | |
50 | ||
51 | struct PLArena { | |
52 | PLArena *next; /* next arena for this lifetime */ | |
53 | PRUword base; /* aligned base address, follows this header */ | |
54 | PRUword limit; /* one beyond last byte in arena */ | |
55 | PRUword avail; /* points to next available byte */ | |
56 | }; | |
57 | ||
58 | #ifdef PL_ARENAMETER | |
59 | typedef struct PLArenaStats PLArenaStats; | |
60 | ||
61 | struct PLArenaStats { | |
62 | PLArenaStats *next; /* next in arenaStats list */ | |
63 | char *name; /* name for debugging */ | |
64 | PRUint32 narenas; /* number of arenas in pool */ | |
65 | PRUint32 nallocs; /* number of PL_ARENA_ALLOCATE() calls */ | |
66 | PRUint32 nreclaims; /* number of reclaims from freeArenas */ | |
67 | PRUint32 nmallocs; /* number of malloc() calls */ | |
68 | PRUint32 ndeallocs; /* number of lifetime deallocations */ | |
69 | PRUint32 ngrows; /* number of PL_ARENA_GROW() calls */ | |
70 | PRUint32 ninplace; /* number of in-place growths */ | |
71 | PRUint32 nreleases; /* number of PL_ARENA_RELEASE() calls */ | |
72 | PRUint32 nfastrels; /* number of "fast path" releases */ | |
73 | PRUint32 nbytes; /* total bytes allocated */ | |
74 | PRUint32 maxalloc; /* maximum allocation size in bytes */ | |
75 | PRFloat64 variance; /* size variance accumulator */ | |
76 | }; | |
77 | #endif | |
78 | ||
79 | struct PLArenaPool { | |
80 | PLArena first; /* first arena in pool list */ | |
81 | PLArena *current; /* arena from which to allocate space */ | |
60c433a9 | 82 | PRUint32 arenasize; /* net exact size of a new arena */ |
b1ab9ed8 A |
83 | PRUword mask; /* alignment mask (power-of-2 - 1) */ |
84 | #ifdef PL_ARENAMETER | |
85 | PLArenaStats stats; | |
86 | #endif | |
87 | }; | |
88 | ||
89 | /* | |
90 | * If the including .c file uses only one power-of-2 alignment, it may define | |
91 | * PL_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions | |
92 | * per ALLOCATE and GROW. | |
93 | */ | |
94 | #ifdef PL_ARENA_CONST_ALIGN_MASK | |
95 | #define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + PL_ARENA_CONST_ALIGN_MASK) \ | |
96 | & ~PL_ARENA_CONST_ALIGN_MASK) | |
97 | ||
98 | #define PL_INIT_ARENA_POOL(pool, name, size) \ | |
99 | PL_InitArenaPool(pool, name, size, PL_ARENA_CONST_ALIGN_MASK + 1) | |
100 | #else | |
101 | #define PL_ARENA_ALIGN(pool, n) (typeof(n))(((PRUword)(n) + (pool)->mask) & ~(pool)->mask) | |
102 | #endif | |
103 | ||
104 | #define PL_ARENA_ALLOCATE(p, pool, nb) \ | |
105 | PR_BEGIN_MACRO \ | |
106 | PLArena *_a = (pool)->current; \ | |
60c433a9 | 107 | typeof((nb)) _nb = PL_ARENA_ALIGN(pool, nb); /* __APPLE__ more to be generic */ \ |
b1ab9ed8 A |
108 | PRUword _p = _a->avail; \ |
109 | PRUword _q = _p + _nb; \ | |
60c433a9 | 110 | if (_nb > (_a->limit - _a->avail)) {/* __APPLE__ */ \ |
b1ab9ed8 | 111 | _p = (PRUword)PL_ArenaAllocate(pool, _nb); \ |
60c433a9 | 112 | } else { \ |
b1ab9ed8 | 113 | _a->avail = _q; \ |
60c433a9 | 114 | } \ |
b1ab9ed8 A |
115 | p = (void *)_p; \ |
116 | PL_ArenaCountAllocation(pool, nb); \ | |
117 | PR_END_MACRO | |
118 | ||
119 | #define PL_ARENA_GROW(p, pool, size, incr) \ | |
120 | PR_BEGIN_MACRO \ | |
121 | PLArena *_a = (pool)->current; \ | |
60c433a9 | 122 | typeof((incr)) _incr = PL_ARENA_ALIGN(pool, incr); /* __APPLE__ more to be generic */ \ |
b1ab9ed8 | 123 | PRUword _p = _a->avail; \ |
60c433a9 | 124 | PRUword _q = _p + _incr; \ |
b1ab9ed8 | 125 | if (_p == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \ |
60c433a9 A |
126 | _incr <= _a->limit - _a->avail) { /* __APPLE__ */\ |
127 | _a->avail = _q; \ | |
b1ab9ed8 A |
128 | PL_ArenaCountInplaceGrowth(pool, size, incr); \ |
129 | } else { \ | |
130 | p = PL_ArenaGrow(pool, p, size, incr); \ | |
131 | } \ | |
132 | PL_ArenaCountGrowth(pool, size, incr); \ | |
133 | PR_END_MACRO | |
134 | ||
135 | #define PL_ARENA_MARK(pool) ((void *) (pool)->current->avail) | |
136 | #define PR_UPTRDIFF(p,q) ((PRUword)(p) - (PRUword)(q)) | |
137 | ||
60c433a9 A |
138 | #define PL_CLEAR_UNUSED_PATTERN(a, pattern) \ |
139 | PR_BEGIN_MACRO \ | |
140 | PR_ASSERT((a)->avail <= (a)->limit); \ | |
141 | memset((void*)(a)->avail, (pattern), (a)->limit - (a)->avail); \ | |
142 | PR_END_MACRO | |
b1ab9ed8 A |
143 | #ifdef DEBUG |
144 | #define PL_FREE_PATTERN 0xDA | |
60c433a9 A |
145 | #define PL_CLEAR_UNUSED(a) PL_CLEAR_UNUSED_PATTERN((a), PL_FREE_PATTERN) |
146 | #define PL_CLEAR_ARENA(a) \ | |
147 | PR_BEGIN_MACRO \ | |
148 | memset((void*)(a), PL_FREE_PATTERN, (a)->limit - (PRUword)(a)); \ | |
149 | PR_END_MACRO | |
b1ab9ed8 A |
150 | #else |
151 | #define PL_CLEAR_UNUSED(a) | |
152 | #define PL_CLEAR_ARENA(a) | |
153 | #endif | |
154 | ||
155 | #if ARENA_MARK_ENABLE | |
156 | ||
157 | #define PL_ARENA_RELEASE(pool, mark) \ | |
158 | PR_BEGIN_MACRO \ | |
159 | char *_m = (char *)(mark); \ | |
160 | PLArena *_a = (pool)->current; \ | |
161 | if (PR_UPTRDIFF(_m, _a->base) <= PR_UPTRDIFF(_a->avail, _a->base)) { \ | |
162 | _a->avail = (PRUword)PL_ARENA_ALIGN(pool, _m); \ | |
163 | PL_CLEAR_UNUSED(_a); \ | |
164 | PL_ArenaCountRetract(pool, _m); \ | |
165 | } else { \ | |
166 | PL_ArenaRelease(pool, _m); \ | |
167 | } \ | |
168 | PL_ArenaCountRelease(pool, _m); \ | |
169 | PR_END_MACRO | |
170 | ||
171 | #else /* !ARENA_MARK_ENABLE */ | |
172 | ||
173 | #define PL_ARENA_RELEASE(pool, mark) | |
174 | ||
175 | #endif /* ARENA_MARK_ENABLE */ | |
176 | ||
177 | #ifdef PL_ARENAMETER | |
178 | #define PL_COUNT_ARENA(pool,op) ((pool)->stats.narenas op) | |
179 | #else | |
180 | #define PL_COUNT_ARENA(pool,op) | |
181 | #endif | |
182 | ||
183 | #define PL_ARENA_DESTROY(pool, a, pnext) \ | |
184 | PR_BEGIN_MACRO \ | |
185 | PL_COUNT_ARENA(pool,--); \ | |
186 | if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ | |
187 | *(pnext) = (a)->next; \ | |
188 | PL_CLEAR_ARENA(a); \ | |
189 | free(a); \ | |
190 | (a) = 0; \ | |
191 | PR_END_MACRO | |
192 | ||
193 | #ifdef PL_ARENAMETER | |
194 | ||
195 | #include <stdio.h> | |
196 | ||
197 | PR_EXTERN(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb); | |
198 | ||
199 | PR_EXTERN(void) PL_ArenaCountInplaceGrowth( | |
200 | PLArenaPool *pool, PRUint32 size, PRUint32 incr); | |
201 | ||
202 | PR_EXTERN(void) PL_ArenaCountGrowth( | |
203 | PLArenaPool *pool, PRUint32 size, PRUint32 incr); | |
204 | ||
205 | PR_EXTERN(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark); | |
206 | ||
207 | PR_EXTERN(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark); | |
208 | ||
209 | PR_EXTERN(void) PL_DumpArenaStats(FILE *fp); | |
210 | ||
211 | #else /* !PL_ARENAMETER */ | |
212 | ||
213 | #define PL_ArenaCountAllocation(ap, nb) /* nothing */ | |
214 | #define PL_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */ | |
215 | #define PL_ArenaCountGrowth(ap, size, incr) /* nothing */ | |
216 | #define PL_ArenaCountRelease(ap, mark) /* nothing */ | |
217 | #define PL_ArenaCountRetract(ap, mark) /* nothing */ | |
218 | ||
219 | #endif /* !PL_ARENAMETER */ | |
220 | ||
221 | PR_END_EXTERN_C | |
222 | ||
223 | #endif /* plarena_h___ */ |