Line data Source code
1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /* Quick arena hack for xpt. */
7 :
8 : /* XXX This exists because we don't want to drag in NSPR. It *seemed*
9 : * to make more sense to write a quick and dirty arena than to clone
10 : * plarena (like js/src did). This is not optimal, but it works.
11 : */
12 :
13 : #include "xpt_arena.h"
14 : #include "mozilla/MemoryReporting.h"
15 : #include <string.h>
16 : #include <stdio.h>
17 : #include <stdlib.h>
18 :
19 : /****************************************************/
20 :
21 : /* Block header for each block in the arena */
22 : struct BLK_HDR
23 : {
24 : BLK_HDR *next;
25 : };
26 :
27 : #define XPT_MIN_BLOCK_SIZE 32
28 :
29 : /* XXX this is lame. Should clone the code to do this bitwise */
30 : #define ALIGN_RND(s,a) ((a)==1?(s):((((s)+(a)-1)/(a))*(a)))
31 :
32 : struct XPTSubArena
33 : {
34 : BLK_HDR *first;
35 : uint8_t *next;
36 : size_t space;
37 : size_t block_size;
38 : };
39 :
40 : struct XPTArena
41 : {
42 : // We have one sub-arena with 8-byte alignment for most allocations, and
43 : // one with 1-byte alignment for C string allocations. The latter sub-arena
44 : // avoids significant amounts of unnecessary padding between C strings.
45 : XPTSubArena subarena8;
46 : XPTSubArena subarena1;
47 : };
48 :
49 : XPT_PUBLIC_API(XPTArena *)
50 3 : XPT_NewArena(size_t block_size8, size_t block_size1)
51 : {
52 3 : XPTArena *arena = static_cast<XPTArena*>(calloc(1, sizeof(XPTArena)));
53 3 : if (arena) {
54 3 : if (block_size8 < XPT_MIN_BLOCK_SIZE)
55 0 : block_size8 = XPT_MIN_BLOCK_SIZE;
56 3 : arena->subarena8.block_size = ALIGN_RND(block_size8, 8);
57 :
58 3 : if (block_size1 < XPT_MIN_BLOCK_SIZE)
59 0 : block_size1 = XPT_MIN_BLOCK_SIZE;
60 3 : arena->subarena1.block_size = block_size1;
61 : }
62 3 : return arena;
63 : }
64 :
65 : static void
66 0 : DestroySubArena(XPTSubArena *subarena)
67 : {
68 0 : BLK_HDR* cur = subarena->first;
69 0 : while (cur) {
70 0 : BLK_HDR* next = cur->next;
71 0 : free(cur);
72 0 : cur = next;
73 : }
74 0 : }
75 :
76 : XPT_PUBLIC_API(void)
77 0 : XPT_DestroyArena(XPTArena *arena)
78 : {
79 0 : DestroySubArena(&arena->subarena8);
80 0 : DestroySubArena(&arena->subarena1);
81 0 : free(arena);
82 0 : }
83 :
84 : /*
85 : * Our alignment rule is that we always round up the size of each allocation
86 : * so that the 'arena->next' pointer one will point to properly aligned space.
87 : */
88 :
89 : XPT_PUBLIC_API(void *)
90 80598 : XPT_ArenaCalloc(XPTArena *arena, size_t size, size_t alignment)
91 : {
92 80598 : if (!size)
93 0 : return NULL;
94 :
95 80598 : if (!arena) {
96 0 : XPT_ASSERT(0);
97 0 : return NULL;
98 : }
99 :
100 : XPTSubArena *subarena;
101 80598 : if (alignment == 8) {
102 40887 : subarena = &arena->subarena8;
103 39711 : } else if (alignment == 1) {
104 39711 : subarena = &arena->subarena1;
105 : } else {
106 0 : XPT_ASSERT(0);
107 0 : return NULL;
108 : }
109 :
110 80598 : size_t bytes = ALIGN_RND(size, alignment);
111 :
112 80598 : if (bytes > subarena->space) {
113 : BLK_HDR* new_block;
114 195 : size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), alignment);
115 195 : size_t new_space = subarena->block_size;
116 :
117 195 : while (bytes > new_space - block_header_size)
118 0 : new_space += subarena->block_size;
119 :
120 : new_block =
121 195 : static_cast<BLK_HDR*>(calloc(new_space / alignment, alignment));
122 195 : if (!new_block) {
123 0 : subarena->next = NULL;
124 0 : subarena->space = 0;
125 0 : return NULL;
126 : }
127 :
128 : /* link block into the list of blocks for use when we destroy */
129 195 : new_block->next = subarena->first;
130 195 : subarena->first = new_block;
131 :
132 : /* set info for current block */
133 195 : subarena->next =
134 195 : reinterpret_cast<uint8_t*>(new_block) + block_header_size;
135 195 : subarena->space = new_space - block_header_size;
136 :
137 : #ifdef DEBUG
138 : /* mark block for corruption check */
139 195 : memset(subarena->next, 0xcd, subarena->space);
140 : #endif
141 : }
142 :
143 : #ifdef DEBUG
144 : {
145 : /* do corruption check */
146 : size_t i;
147 2540739 : for (i = 0; i < bytes; ++i) {
148 2460141 : XPT_ASSERT(subarena->next[i] == 0xcd);
149 : }
150 : /* we guarantee that the block will be filled with zeros */
151 80598 : memset(subarena->next, 0, bytes);
152 : }
153 : #endif
154 :
155 80598 : uint8_t* p = subarena->next;
156 80598 : subarena->next += bytes;
157 80598 : subarena->space -= bytes;
158 :
159 80598 : return p;
160 : }
161 :
162 : /***************************************************************************/
163 :
164 : #ifdef DEBUG
165 : XPT_PUBLIC_API(void)
166 0 : XPT_AssertFailed(const char *s, const char *file, uint32_t lineno)
167 : {
168 : fprintf(stderr, "Assertion failed: %s, file %s, line %d\n",
169 0 : s, file, lineno);
170 0 : abort();
171 : }
172 : #endif
173 :
174 : static size_t
175 0 : SizeOfSubArenaExcludingThis(XPTSubArena *subarena, MozMallocSizeOf mallocSizeOf)
176 : {
177 0 : size_t n = 0;
178 :
179 0 : BLK_HDR* cur = subarena->first;
180 0 : while (cur) {
181 0 : BLK_HDR* next = cur->next;
182 0 : n += mallocSizeOf(cur);
183 0 : cur = next;
184 : }
185 :
186 0 : return n;
187 : }
188 :
189 : XPT_PUBLIC_API(size_t)
190 0 : XPT_SizeOfArenaIncludingThis(XPTArena *arena, MozMallocSizeOf mallocSizeOf)
191 : {
192 0 : size_t n = mallocSizeOf(arena);
193 0 : n += SizeOfSubArenaExcludingThis(&arena->subarena8, mallocSizeOf);
194 0 : n += SizeOfSubArenaExcludingThis(&arena->subarena1, mallocSizeOf);
195 0 : return n;
196 : }
|