| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | #include "Python.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-02 21:41:18 +00:00
										 |  |  | /* A simple arena block structure.
 | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    Measurements with standard library modules suggest the average | 
					
						
							|  |  |  |    allocation is about 20 bytes and that most compiles use a single | 
					
						
							|  |  |  |    block. | 
					
						
							| 
									
										
										
										
											2006-04-21 10:40:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    TODO(jhylton): Think about a realloc API, maybe just for the last | 
					
						
							|  |  |  |    allocation? | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | */ | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 17:53:04 +00:00
										 |  |  | #define DEFAULT_BLOCK_SIZE 8192
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | #define ALIGNMENT               8
 | 
					
						
							|  |  |  | #define ALIGNMENT_MASK          (ALIGNMENT - 1)
 | 
					
						
							|  |  |  | #define ROUNDUP(x)              (((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK)
 | 
					
						
							| 
									
										
										
										
											2006-04-21 10:40:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 17:53:04 +00:00
										 |  |  | typedef struct _block { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /* Total number of bytes owned by this block available to pass out.
 | 
					
						
							|  |  |  |      * Read-only after initialization.  The first such byte starts at | 
					
						
							|  |  |  |      * ab_mem. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     size_t ab_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Total number of bytes already passed out.  The next byte available
 | 
					
						
							|  |  |  |      * to pass out starts at ab_mem + ab_offset. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     size_t ab_offset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* An arena maintains a singly-linked, NULL-terminated list of
 | 
					
						
							|  |  |  |      * all blocks owned by the arena.  These are linked via the | 
					
						
							|  |  |  |      * ab_next member. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     struct _block *ab_next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Pointer to the first allocatable byte owned by this block.  Read-
 | 
					
						
							|  |  |  |      * only after initialization. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     void *ab_mem; | 
					
						
							| 
									
										
										
										
											2006-02-28 17:53:04 +00:00
										 |  |  | } block; | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 18:52:28 +00:00
										 |  |  | /* The arena manages two kinds of memory, blocks of raw memory
 | 
					
						
							|  |  |  |    and a list of PyObject* pointers.  PyObjects are decrefed | 
					
						
							|  |  |  |    when the arena is freed. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2006-03-02 20:37:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | struct _arena { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /* Pointer to the first block allocated for the arena, never NULL.
 | 
					
						
							|  |  |  |        It is used only to find the first block when the arena is | 
					
						
							|  |  |  |        being freed. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     block *a_head; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Pointer to the block currently used for allocation.  It's
 | 
					
						
							|  |  |  |        ab_next field should be NULL.  If it is not-null after a | 
					
						
							|  |  |  |        call to block_alloc(), it means a new block has been allocated | 
					
						
							|  |  |  |        and a_cur should be reset to point it. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     block *a_cur; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* A Python list object containing references to all the PyObject
 | 
					
						
							|  |  |  |        pointers associated with this area.  They will be DECREFed | 
					
						
							|  |  |  |        when the arena is freed. | 
					
						
							|  |  |  |     */ | 
					
						
							|  |  |  |     PyObject *a_objects; | 
					
						
							| 
									
										
										
										
											2006-04-21 10:40:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /* Debug output */ | 
					
						
							|  |  |  |     size_t total_allocs; | 
					
						
							|  |  |  |     size_t total_size; | 
					
						
							|  |  |  |     size_t total_blocks; | 
					
						
							|  |  |  |     size_t total_block_size; | 
					
						
							|  |  |  |     size_t total_big_blocks; | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 17:53:04 +00:00
										 |  |  | static block * | 
					
						
							|  |  |  | block_new(size_t size) | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /* Allocate header and block as one unit.
 | 
					
						
							|  |  |  |        ab_mem points just past header. */ | 
					
						
							|  |  |  |     block *b = (block *)malloc(sizeof(block) + size); | 
					
						
							|  |  |  |     if (!b) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     b->ab_size = size; | 
					
						
							|  |  |  |     b->ab_mem = (void *)(b + 1); | 
					
						
							|  |  |  |     b->ab_next = NULL; | 
					
						
							|  |  |  |     b->ab_offset = ROUNDUP((Py_uintptr_t)(b->ab_mem)) - | 
					
						
							|  |  |  |       (Py_uintptr_t)(b->ab_mem); | 
					
						
							|  |  |  |     return b; | 
					
						
							| 
									
										
										
										
											2006-02-28 17:53:04 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | block_free(block *b) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     while (b) { | 
					
						
							|  |  |  |         block *next = b->ab_next; | 
					
						
							|  |  |  |         free(b); | 
					
						
							|  |  |  |         b = next; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 17:53:04 +00:00
										 |  |  | static void * | 
					
						
							|  |  |  | block_alloc(block *b, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     void *p; | 
					
						
							|  |  |  |     assert(b); | 
					
						
							|  |  |  |     size = ROUNDUP(size); | 
					
						
							|  |  |  |     if (b->ab_offset + size > b->ab_size) { | 
					
						
							|  |  |  |         /* If we need to allocate more memory than will fit in
 | 
					
						
							|  |  |  |            the default block, allocate a one-off block that is | 
					
						
							|  |  |  |            exactly the right size. */ | 
					
						
							|  |  |  |         /* TODO(jhylton): Think about space waste at end of block */ | 
					
						
							|  |  |  |         block *newbl = block_new( | 
					
						
							|  |  |  |                         size < DEFAULT_BLOCK_SIZE ? | 
					
						
							|  |  |  |                         DEFAULT_BLOCK_SIZE : size); | 
					
						
							|  |  |  |         if (!newbl) | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         assert(!b->ab_next); | 
					
						
							|  |  |  |         b->ab_next = newbl; | 
					
						
							|  |  |  |         b = newbl; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert(b->ab_offset + size <= b->ab_size); | 
					
						
							|  |  |  |     p = (void *)(((char *)b->ab_mem) + b->ab_offset); | 
					
						
							|  |  |  |     b->ab_offset += size; | 
					
						
							|  |  |  |     return p; | 
					
						
							| 
									
										
										
										
											2006-02-28 17:53:04 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | PyArena * | 
					
						
							|  |  |  | PyArena_New() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyArena* arena = (PyArena *)malloc(sizeof(PyArena)); | 
					
						
							|  |  |  |     if (!arena) | 
					
						
							|  |  |  |         return (PyArena*)PyErr_NoMemory(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     arena->a_head = block_new(DEFAULT_BLOCK_SIZE); | 
					
						
							|  |  |  |     arena->a_cur = arena->a_head; | 
					
						
							|  |  |  |     if (!arena->a_head) { | 
					
						
							|  |  |  |         free((void *)arena); | 
					
						
							|  |  |  |         return (PyArena*)PyErr_NoMemory(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     arena->a_objects = PyList_New(0); | 
					
						
							|  |  |  |     if (!arena->a_objects) { | 
					
						
							|  |  |  |         block_free(arena->a_head); | 
					
						
							|  |  |  |         free((void *)arena); | 
					
						
							|  |  |  |         return (PyArena*)PyErr_NoMemory(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     arena->total_allocs = 0; | 
					
						
							|  |  |  |     arena->total_size = 0; | 
					
						
							|  |  |  |     arena->total_blocks = 1; | 
					
						
							|  |  |  |     arena->total_block_size = DEFAULT_BLOCK_SIZE; | 
					
						
							|  |  |  |     arena->total_big_blocks = 0; | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return arena; | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | PyArena_Free(PyArena *arena) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     int r; | 
					
						
							|  |  |  |     assert(arena); | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /*
 | 
					
						
							|  |  |  |     fprintf(stderr, | 
					
						
							|  |  |  |         "alloc=%d size=%d blocks=%d block_size=%d big=%d objects=%d\n", | 
					
						
							|  |  |  |         arena->total_allocs, arena->total_size, arena->total_blocks, | 
					
						
							|  |  |  |         arena->total_block_size, arena->total_big_blocks, | 
					
						
							|  |  |  |         PyList_Size(arena->a_objects)); | 
					
						
							|  |  |  |     */ | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     block_free(arena->a_head); | 
					
						
							|  |  |  |     /* This property normally holds, except when the code being compiled
 | 
					
						
							|  |  |  |        is sys.getobjects(0), in which case there will be two references. | 
					
						
							|  |  |  |     assert(arena->a_objects->ob_refcnt == 1); | 
					
						
							|  |  |  |     */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Clear all the elements from the list.  This is necessary
 | 
					
						
							|  |  |  |        to guarantee that they will be DECREFed. */ | 
					
						
							|  |  |  |     r = PyList_SetSlice(arena->a_objects, | 
					
						
							|  |  |  |                         0, PyList_GET_SIZE(arena->a_objects), NULL); | 
					
						
							|  |  |  |     assert(r == 0); | 
					
						
							|  |  |  |     assert(PyList_GET_SIZE(arena->a_objects) == 0); | 
					
						
							|  |  |  |     Py_DECREF(arena->a_objects); | 
					
						
							|  |  |  |     free(arena); | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void * | 
					
						
							| 
									
										
										
										
											2006-03-02 20:37:32 +00:00
										 |  |  | PyArena_Malloc(PyArena *arena, size_t size) | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     void *p = block_alloc(arena->a_cur, size); | 
					
						
							|  |  |  |     if (!p) | 
					
						
							|  |  |  |         return PyErr_NoMemory(); | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     arena->total_allocs++; | 
					
						
							|  |  |  |     arena->total_size += size; | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /* Reset cur if we allocated a new block. */ | 
					
						
							|  |  |  |     if (arena->a_cur->ab_next) { | 
					
						
							|  |  |  |         arena->a_cur = arena->a_cur->ab_next; | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         arena->total_blocks++; | 
					
						
							|  |  |  |         arena->total_block_size += arena->a_cur->ab_size; | 
					
						
							|  |  |  |         if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE) | 
					
						
							|  |  |  |             ++arena->total_big_blocks; | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return p; | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2006-03-02 20:37:32 +00:00
										 |  |  | PyArena_AddPyObject(PyArena *arena, PyObject *obj) | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     int r = PyList_Append(arena->a_objects, obj); | 
					
						
							|  |  |  |     if (r >= 0) { | 
					
						
							|  |  |  |         Py_DECREF(obj); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return r; | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | } |