ViewVC Help
View File | Revision Log | View Changeset | Root Listing
root/Oni2/XmlTools2/trunk/libs/pool_allocator.cpp
Revision: 906
Committed: Sat Feb 1 14:27:58 2014 UTC (11 years, 8 months ago) by s10k
Content type: text/x-c++src
File size: 7864 byte(s)
Log Message:

File Contents

# Content
1 /*
2 * 42TinyJS
3 *
4 * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
5 *
6 * Authored By Armin Diedering <armin@diedering.de>
7 *
8 * Copyright (C) 2010-2013 ardisoft
9 *
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy of
12 * this software and associated documentation files (the "Software"), to deal in
13 * the Software without restriction, including without limitation the rights to
14 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
15 * of the Software, and to permit persons to whom the Software is furnished to do
16 * so, subject to the following conditions:
17
18 * The above copyright notice and this permission notice shall be included in all
19 * copies or substantial portions of the Software.
20
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30 #include "pool_allocator.h"
31 #include <vector>
32 #include <algorithm>
33 #include <stdio.h>
34
35 struct block {
36 block* next;
37 };
38 struct block_head {
39 block_head* next;
40 };
41
42 static void set_next(void* p, void* next) {
43 static_cast<block*>(p)->next = static_cast<block*>(next);
44 }
45
46 static void* get_next(void* p) {
47 return static_cast<block*>(p)->next;
48 }
49
50 fixed_size_allocator::fixed_size_allocator( size_t numObjects, size_t objectSize, const char *for_class )
51 {
52 num_objects = numObjects;
53 object_size = objectSize >= sizeof(block) ? objectSize : sizeof(block);
54
55 head_of_free_list = head = 0;
56
57 #ifdef DEBUG_POOL_ALLOCATOR
58 if(for_class) name = for_class;
59 allocs=
60 frees=
61 max =
62 current=
63 blocks =
64 #endif
65 refs = 0;
66 }
67
68 fixed_size_allocator::~fixed_size_allocator()
69 {
70 while(head) {
71 char *p = (char*)head;
72 head = head->next;
73 delete [] p;
74 }
75 #ifdef DEBUG_POOL_ALLOCATOR
76 # ifndef LOG_POOL_ALLOCATOR_MEMORY_USAGE
77 if(refs) {
78 # endif
79 fprintf(stderr, "allocator [%s](%d) destroyed\n", name.c_str(), object_size);
80 fprintf(stderr, " allocs:%i, ", allocs);
81 fprintf(stderr, "frees:%i, ", frees);
82 fprintf(stderr, "max:%i, ", max);
83 fprintf(stderr, "blocks:%i\n", blocks);
84 if(refs) fprintf(stderr, "************ %i x not freed ************\n", refs);
85 fprintf(stderr, "\n");
86 # ifndef LOG_POOL_ALLOCATOR_MEMORY_USAGE
87 }
88 # endif
89 #endif
90 }
91
92 void* fixed_size_allocator::_alloc( size_t ) {
93 refs++;
94 #ifdef DEBUG_POOL_ALLOCATOR
95 allocs++;current++;
96 if(current>max)max=current;
97 #endif
98 void* p = head_of_free_list;
99 if(p) {
100 head_of_free_list = get_next(p);
101 } else {
102
103 char* new_block = new char[sizeof(block_head) + num_objects * object_size];
104 ((block_head*)new_block)->next = head;
105 head = (block_head*)new_block;
106 new_block += sizeof(block_head);
107 for(std::size_t i = object_size; i < (num_objects - 1) * object_size; i += object_size) {
108 set_next(&new_block[i], &new_block[i + object_size]);
109 }
110 set_next(&new_block[(num_objects - 1) * object_size], 0);
111 p = new_block;
112 head_of_free_list = &new_block[object_size];
113
114 #ifdef DEBUG_POOL_ALLOCATOR
115 blocks++;
116 #endif
117 }
118 return p;
119 }
120 #include <assert.h>
121 #ifndef ASSERT
122 # define ASSERT(X) assert(X)
123 #endif
124
125 bool fixed_size_allocator::_free( void* p, size_t ) {
126 if(p == 0) return refs==0;
127 refs--;
128 #ifdef DEBUG_POOL_ALLOCATOR
129 ASSERT(refs>=0);
130 frees++;current--;
131 #endif
132 block* dead_object = static_cast<block*>(p);
133
134 dead_object->next = static_cast<block*>(head_of_free_list);
135 head_of_free_list = dead_object;
136 return refs==0;
137 }
138 typedef std::vector<fixed_size_allocator*> allocator_pool_t;
139 typedef allocator_pool_t::iterator allocator_pool_it;
140
141 static bool compare_allocator_pool(fixed_size_allocator *allocator, size_t Size) {
142 return allocator->objectSize() < Size;
143 }
144
145 static class _allocator_pool
146 {
147 public:
148 _allocator_pool() : allocator_pool(0) {
149 #ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
150 last_ok = last_access = 0;
151 #endif
152 }
153 ~_allocator_pool() {
154 if(allocator_pool && !allocator_pool->empty())
155 for(allocator_pool_it it = allocator_pool->begin(); it!=allocator_pool->end(); it++)
156 delete *it;
157 delete allocator_pool;
158 #ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
159 if(last_access) fprintf(stderr, "last_ok:%i(%i)=%i%%\n", last_ok, last_access, (last_ok*100)/last_access);
160 #endif
161 }
162 allocator_pool_it *findAllocator(size_t size, allocator_pool_it &it) {
163 if(!allocator_pool) return 0;
164 it = lower_bound(allocator_pool->begin(), allocator_pool->end(), size, compare_allocator_pool);
165 if(it != allocator_pool->end() && (*it)->objectSize() == size)
166 return &it;
167 return 0;
168 }
169 fixed_size_allocator *checkLastAllocator(size_t size) {
170 #ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
171 last_access++;
172 #endif
173 if(last_allocate_allocator && last_allocate_allocator->objectSize()==size) {
174 #ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
175 last_ok++;
176 #endif
177 return last_allocate_allocator;
178 }
179 else if(last_free_allocator && last_free_allocator->objectSize()==size) {
180 #ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
181 last_ok++;
182 #endif
183 return last_free_allocator;
184 } else
185 return 0;
186 }
187 void removeAllocator(allocator_pool_it it) {
188 if(last_allocate_allocator == *it) last_allocate_allocator = 0;
189 if(last_free_allocator == *it) last_free_allocator = 0;
190 delete *it; allocator_pool->erase(it);
191 if(allocator_pool->empty()) {
192 delete allocator_pool; allocator_pool=0;
193 }
194 }
195 allocator_pool_t *allocator_pool;
196 fixed_size_allocator *last_allocate_allocator;
197 fixed_size_allocator *last_free_allocator;
198 #ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
199 int last_ok;
200 int last_access;
201 #endif
202 }allocator_pool;
203
204 //#define WITH_TIME_LOGGER
205 #include "time_logger.h"
206
207 TimeLoggerCreate(alloc, false);
208 TimeLoggerCreate(free, false);
209 #ifdef NO_THREADING
210 # define LOCK do{}while(0)
211 #else
212 CScriptMutex fixed_size_allocator::locker;
213 class lock_help {
214 public:
215 lock_help() { fixed_size_allocator::locker.lock(); }
216 ~lock_help() { fixed_size_allocator::locker.unlock(); }
217 };
218 #define LOCK lock_help lock
219 #endif
220 void* fixed_size_allocator::alloc(size_t size, const char *for_class) {
221 TimeLoggerHelper(alloc);
222 LOCK;
223 if(!allocator_pool.allocator_pool) {
224 allocator_pool.allocator_pool = new allocator_pool_t();
225 allocator_pool.last_allocate_allocator = allocator_pool.last_free_allocator = 0;
226 }
227 fixed_size_allocator *last = allocator_pool.checkLastAllocator(size);
228 if(last)
229 return last->_alloc(size);
230 else {
231 allocator_pool_it it; if(allocator_pool.findAllocator(size, it))
232 return (allocator_pool.last_allocate_allocator = *(it))->_alloc(size);
233 else {
234 return (allocator_pool.last_allocate_allocator = (*allocator_pool.allocator_pool->insert(it, new fixed_size_allocator(64, size, for_class))))->_alloc(size);
235 }
236 }
237 }
238 void fixed_size_allocator::free(void *p, size_t size) {
239 TimeLoggerHelper(free);
240 LOCK;
241 if(!allocator_pool.allocator_pool) {
242 ASSERT(0/* free called but not allocator defined*/);
243 return;
244 }
245 fixed_size_allocator *last = allocator_pool.checkLastAllocator(size);
246 if(last) {
247 if( last->_free(p, size) ) {
248 allocator_pool_it it; if(allocator_pool.findAllocator(size, it))
249 allocator_pool.removeAllocator(it);
250 }
251 } else {
252 allocator_pool_it it; if(allocator_pool.findAllocator(size, it)) {
253 if( (allocator_pool.last_free_allocator = *it)->_free(p, size) )
254 allocator_pool.removeAllocator(it);
255 } else
256 ASSERT(0/* free called but not allocator defined*/);
257 }
258 }