| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | #include "Python.h"
 | 
					
						
							|  |  |  | #include "pyarena.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-03-31 16:41:22 +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
 | 
					
						
							| 
									
										
										
										
											2006-04-13 19:16:13 +00:00
										 |  |  | #define ALIGNMENT		8
 | 
					
						
							|  |  |  | #define ALIGNMENT_MASK		(ALIGNMENT - 1)
 | 
					
						
							|  |  |  | #define ROUNDUP(x)		(((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 17:53:04 +00:00
										 |  |  | typedef struct _block { | 
					
						
							| 
									
										
										
										
											2006-03-02 21:41:18 +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. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	size_t ab_size; | 
					
						
							| 
									
										
										
										
											2006-03-02 21:41:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Total number of bytes already passed out.  The next byte available
 | 
					
						
							|  |  |  | 	 * to pass out starts at ab_mem + ab_offset. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	size_t ab_offset; | 
					
						
							| 
									
										
										
										
											2006-03-02 21:41:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* An arena maintains a singly-linked, NULL-terminated list of
 | 
					
						
							|  |  |  | 	 * all blocks owned by the arena.  These are linked via the | 
					
						
							|  |  |  | 	 * ab_next member. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	struct _block *ab_next; | 
					
						
							| 
									
										
										
										
											2006-03-02 21:41:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Pointer to the first allocatable byte owned by this block.  Read-
 | 
					
						
							|  |  |  | 	 * only after initialization. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2006-03-31 16:41:22 +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. | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	block *a_head; | 
					
						
							| 
									
										
										
										
											2006-03-31 16:41:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* 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. | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	block *a_cur; | 
					
						
							| 
									
										
										
										
											2006-03-31 16:41:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* A Python list object containing references to all the PyObject
 | 
					
						
							|  |  |  |            pointers associated with this area.  They will be DECREFed | 
					
						
							|  |  |  |            when the arena is freed. | 
					
						
							|  |  |  |         */ | 
					
						
							| 
									
										
										
										
											2006-02-28 18:52:28 +00:00
										 |  |  |         PyObject *a_objects; | 
					
						
							| 
									
										
										
										
											2006-03-31 16:41:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							|  |  |  |         /* Debug output */ | 
					
						
							|  |  |  |         size_t total_allocs; | 
					
						
							|  |  |  |         size_t total_size; | 
					
						
							|  |  |  |         size_t total_blocks; | 
					
						
							|  |  |  |         size_t total_block_size; | 
					
						
							|  |  |  |         size_t total_big_blocks; | 
					
						
							|  |  |  | #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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-03-02 20:37:32 +00:00
										 |  |  | 	/* Allocate header and block as one unit.
 | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	   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; | 
					
						
							| 
									
										
										
										
											2006-04-13 19:16:13 +00:00
										 |  |  | 	b->ab_offset = ROUNDUP((Py_uintptr_t)(b->ab_mem)) -  | 
					
						
							|  |  |  | 	  (Py_uintptr_t)(b->ab_mem); | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	return b; | 
					
						
							| 
									
										
										
										
											2006-02-28 17:53:04 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | block_free(block *b) { | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	void *p; | 
					
						
							|  |  |  | 	assert(b); | 
					
						
							| 
									
										
										
										
											2006-04-13 19:16:13 +00:00
										 |  |  | 	size = ROUNDUP(size); | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	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 */ | 
					
						
							| 
									
										
										
										
											2006-04-11 12:01:56 +00:00
										 |  |  | 		block *newbl = block_new( | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 				size < DEFAULT_BLOCK_SIZE ? | 
					
						
							|  |  |  | 				DEFAULT_BLOCK_SIZE : size); | 
					
						
							| 
									
										
										
										
											2006-04-11 12:01:56 +00:00
										 |  |  | 		if (!newbl) | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 			return NULL; | 
					
						
							|  |  |  | 		assert(!b->ab_next); | 
					
						
							| 
									
										
										
										
											2006-04-11 12:01:56 +00:00
										 |  |  | 		b->ab_next = newbl; | 
					
						
							|  |  |  | 		b = newbl; | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	PyArena* arena = (PyArena *)malloc(sizeof(PyArena)); | 
					
						
							|  |  |  | 	if (!arena) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	arena->a_head = block_new(DEFAULT_BLOCK_SIZE); | 
					
						
							|  |  |  | 	arena->a_cur = arena->a_head; | 
					
						
							| 
									
										
										
										
											2006-02-28 18:52:28 +00:00
										 |  |  |         if (!arena->a_head) { | 
					
						
							|  |  |  |                 free((void *)arena); | 
					
						
							|  |  |  |                 return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  |         arena->a_objects = PyList_New(0); | 
					
						
							| 
									
										
										
										
											2006-02-28 18:52:28 +00:00
										 |  |  |         if (!arena->a_objects) { | 
					
						
							|  |  |  |                 block_free(arena->a_head); | 
					
						
							|  |  |  |                 free((void *)arena); | 
					
						
							|  |  |  |                 return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							|  |  |  |         arena->total_allocs = 0; | 
					
						
							|  |  |  |         arena->total_size = 0; | 
					
						
							|  |  |  |         arena->total_blocks = 1; | 
					
						
							|  |  |  |         arena->total_block_size = DEFAULT_BLOCK_SIZE; | 
					
						
							|  |  |  |         arena->total_big_blocks = 0; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	return arena; | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | PyArena_Free(PyArena *arena) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-03-31 16:41:22 +00:00
										 |  |  |         int r; | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	assert(arena); | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							| 
									
										
										
										
											2006-03-02 20:37:32 +00:00
										 |  |  |         fprintf(stderr, | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  |                 "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)); | 
					
						
							|  |  |  |         */ | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	block_free(arena->a_head); | 
					
						
							| 
									
										
										
										
											2006-02-28 18:52:28 +00:00
										 |  |  |         assert(arena->a_objects->ob_refcnt == 1); | 
					
						
							| 
									
										
										
										
											2006-03-31 16:41:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* 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); | 
					
						
							| 
									
										
										
										
											2006-02-28 18:52:28 +00:00
										 |  |  |         Py_DECREF(arena->a_objects); | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +00:00
										 |  |  | 	void *p = block_alloc(arena->a_cur, size); | 
					
						
							|  |  |  | 	if (!p) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							|  |  |  |         arena->total_allocs++; | 
					
						
							|  |  |  |         arena->total_size += size; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +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)
 | 
					
						
							|  |  |  |                 arena->total_blocks++; | 
					
						
							|  |  |  |                 arena->total_block_size += arena->a_cur->ab_size; | 
					
						
							|  |  |  |                 if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE) | 
					
						
							| 
									
										
										
										
											2006-03-02 21:14:45 +00:00
										 |  |  |                         ++arena->total_big_blocks; | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-02-28 18:29:00 +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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-03-01 15:02:24 +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
										 |  |  | } |