source: XmlTools2/trunk/libs/pool_allocator.cpp@ 921

Last change on this file since 921 was 906, checked in by s10k, 11 years ago
File size: 7.7 KB
RevLine 
[906]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
35struct block {
36 block* next;
37};
38struct block_head {
39 block_head* next;
40};
41
42static void set_next(void* p, void* next) {
43 static_cast<block*>(p)->next = static_cast<block*>(next);
44}
45
46static void* get_next(void* p) {
47 return static_cast<block*>(p)->next;
48}
49
50fixed_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
68fixed_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
92void* 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
125bool 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}
138typedef std::vector<fixed_size_allocator*> allocator_pool_t;
139typedef allocator_pool_t::iterator allocator_pool_it;
140
141static bool compare_allocator_pool(fixed_size_allocator *allocator, size_t Size) {
142 return allocator->objectSize() < Size;
143}
144
145static class _allocator_pool
146{
147public:
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
207TimeLoggerCreate(alloc, false);
208TimeLoggerCreate(free, false);
209#ifdef NO_THREADING
210# define LOCK do{}while(0)
211#else
212CScriptMutex fixed_size_allocator::locker;
213class lock_help {
214public:
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
220void* 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}
238void 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}
Note: See TracBrowser for help on using the repository browser.