| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | #include "Python.h"
 | 
					
						
							| 
									
										
										
										
											2021-03-24 02:23:01 +01:00
										 |  |  | #include "pycore_pyarena.h"       // PyArena
 | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2024-11-07 07:37:41 -08:00
										 |  |  |    allocation is about 20 bytes and that most compilers use a single | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  |    block. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											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
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-20 05:30:03 +08:00
										 |  |  |     /* Pointer to the block currently used for allocation.  Its
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |        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
 | 
					
						
							| 
									
										
										
										
											2018-10-20 05:30:03 +08:00
										 |  |  |        pointers associated with this arena.  They will be DECREFed | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |        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. */ | 
					
						
							| 
									
										
										
										
											2013-07-07 17:18:53 +02:00
										 |  |  |     block *b = (block *)PyMem_Malloc(sizeof(block) + size); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (!b) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     b->ab_size = size; | 
					
						
							|  |  |  |     b->ab_mem = (void *)(b + 1); | 
					
						
							|  |  |  |     b->ab_next = NULL; | 
					
						
							| 
									
										
										
										
											2012-09-20 20:56:47 +02:00
										 |  |  |     b->ab_offset = (char *)_Py_ALIGN_UP(b->ab_mem, ALIGNMENT) - | 
					
						
							|  |  |  |             (char *)(b->ab_mem); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2013-07-07 17:18:53 +02:00
										 |  |  |         PyMem_Free(b); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         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); | 
					
						
							| 
									
										
										
										
											2012-09-20 20:56:47 +02:00
										 |  |  |     size = _Py_SIZE_ROUND_UP(size, ALIGNMENT); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +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. */ | 
					
						
							|  |  |  |         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 * | 
					
						
							| 
									
										
										
										
											2021-03-24 02:23:01 +01:00
										 |  |  | _PyArena_New(void) | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-07-07 17:18:53 +02:00
										 |  |  |     PyArena* arena = (PyArena *)PyMem_Malloc(sizeof(PyArena)); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (!arena) | 
					
						
							|  |  |  |         return (PyArena*)PyErr_NoMemory(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     arena->a_head = block_new(DEFAULT_BLOCK_SIZE); | 
					
						
							|  |  |  |     arena->a_cur = arena->a_head; | 
					
						
							|  |  |  |     if (!arena->a_head) { | 
					
						
							| 
									
										
										
										
											2013-07-07 17:18:53 +02:00
										 |  |  |         PyMem_Free((void *)arena); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         return (PyArena*)PyErr_NoMemory(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     arena->a_objects = PyList_New(0); | 
					
						
							|  |  |  |     if (!arena->a_objects) { | 
					
						
							|  |  |  |         block_free(arena->a_head); | 
					
						
							| 
									
										
										
										
											2013-07-07 17:18:53 +02:00
										 |  |  |         PyMem_Free((void *)arena); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											2021-03-24 02:23:01 +01:00
										 |  |  | _PyArena_Free(PyArena *arena) | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     assert(arena); | 
					
						
							| 
									
										
										
										
											2006-02-28 19:57:06 +00:00
										 |  |  | #if defined(Py_DEBUG)
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /*
 | 
					
						
							|  |  |  |     fprintf(stderr, | 
					
						
							| 
									
										
										
										
											2019-03-13 22:59:55 +02:00
										 |  |  |         "alloc=%zu size=%zu blocks=%zu block_size=%zu big=%zu objects=%zu\n", | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         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); | 
					
						
							|  |  |  |     */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_DECREF(arena->a_objects); | 
					
						
							| 
									
										
										
										
											2013-07-07 17:18:53 +02:00
										 |  |  |     PyMem_Free(arena); | 
					
						
							| 
									
										
										
										
											2005-12-17 20:54:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void * | 
					
						
							| 
									
										
										
										
											2021-03-24 02:23:01 +01: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 | 
					
						
							| 
									
										
										
										
											2021-03-24 02:23:01 +01: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
										 |  |  | } |