1 // Stack of Python objects 2 3 #include "Python.h" 4 #include "pycore_freelist.h" 5 #include "pycore_pystate.h" 6 #include "pycore_object_stack.h" 7 8 extern _PyObjectStackChunk *_PyObjectStackChunk_New(void); 9 extern void _PyObjectStackChunk_Free(_PyObjectStackChunk *); 10 11 static struct _Py_object_stack_freelist * get_object_stack_freelist(void)12get_object_stack_freelist(void) 13 { 14 struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); 15 return &freelists->object_stacks; 16 } 17 18 _PyObjectStackChunk * _PyObjectStackChunk_New(void)19_PyObjectStackChunk_New(void) 20 { 21 _PyObjectStackChunk *buf; 22 struct _Py_object_stack_freelist *obj_stack_freelist = get_object_stack_freelist(); 23 if (obj_stack_freelist->numfree > 0) { 24 buf = obj_stack_freelist->items; 25 obj_stack_freelist->items = buf->prev; 26 obj_stack_freelist->numfree--; 27 } 28 else { 29 // NOTE: we use PyMem_RawMalloc() here because this is used by the GC 30 // during mimalloc heap traversal. In that context, it is not safe to 31 // allocate mimalloc memory, such as via PyMem_Malloc(). 32 buf = PyMem_RawMalloc(sizeof(_PyObjectStackChunk)); 33 if (buf == NULL) { 34 return NULL; 35 } 36 } 37 buf->prev = NULL; 38 buf->n = 0; 39 return buf; 40 } 41 42 void _PyObjectStackChunk_Free(_PyObjectStackChunk * buf)43_PyObjectStackChunk_Free(_PyObjectStackChunk *buf) 44 { 45 assert(buf->n == 0); 46 struct _Py_object_stack_freelist *obj_stack_freelist = get_object_stack_freelist(); 47 if (obj_stack_freelist->numfree >= 0 && 48 obj_stack_freelist->numfree < _PyObjectStackChunk_MAXFREELIST) 49 { 50 buf->prev = obj_stack_freelist->items; 51 obj_stack_freelist->items = buf; 52 obj_stack_freelist->numfree++; 53 } 54 else { 55 PyMem_RawFree(buf); 56 } 57 } 58 59 void _PyObjectStack_Clear(_PyObjectStack * queue)60_PyObjectStack_Clear(_PyObjectStack *queue) 61 { 62 while (queue->head != NULL) { 63 _PyObjectStackChunk *buf = queue->head; 64 buf->n = 0; 65 queue->head = buf->prev; 66 _PyObjectStackChunk_Free(buf); 67 } 68 } 69 70 void _PyObjectStack_Merge(_PyObjectStack * dst,_PyObjectStack * src)71_PyObjectStack_Merge(_PyObjectStack *dst, _PyObjectStack *src) 72 { 73 if (src->head == NULL) { 74 return; 75 } 76 77 if (dst->head != NULL) { 78 // First, append dst to the bottom of src 79 _PyObjectStackChunk *last = src->head; 80 while (last->prev != NULL) { 81 last = last->prev; 82 } 83 last->prev = dst->head; 84 } 85 86 // Now that src has all the chunks, set dst to src 87 dst->head = src->head; 88 src->head = NULL; 89 } 90 91 void _PyObjectStackChunk_ClearFreeList(struct _Py_object_freelists * freelists,int is_finalization)92_PyObjectStackChunk_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization) 93 { 94 if (!is_finalization) { 95 // Ignore requests to clear the free list during GC. We use object 96 // stacks during GC, so emptying the free-list is counterproductive. 97 return; 98 } 99 100 struct _Py_object_stack_freelist *freelist = &freelists->object_stacks; 101 while (freelist->numfree > 0) { 102 _PyObjectStackChunk *buf = freelist->items; 103 freelist->items = buf->prev; 104 freelist->numfree--; 105 PyMem_RawFree(buf); 106 } 107 freelist->numfree = -1; 108 } 109