diff options
Diffstat (limited to 'Python/pyarena.c')
| -rw-r--r-- | Python/pyarena.c | 46 | 
1 files changed, 41 insertions, 5 deletions
diff --git a/Python/pyarena.c b/Python/pyarena.c index 242ca1d67d..f11a90546b 100644 --- a/Python/pyarena.c +++ b/Python/pyarena.c @@ -6,9 +6,16 @@     Measurements with standard library modules suggest the average     allocation is about 20 bytes and that most compiles use a single     block. + +   TODO(jhylton): Think about a realloc API, maybe just for the last +   allocation?  */  #define DEFAULT_BLOCK_SIZE 8192 +#define ALIGNMENT		8 +#define ALIGNMENT_MASK		(ALIGNMENT - 1) +#define ROUNDUP(x)		(((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK) +  typedef struct _block {  	/* Total number of bytes owned by this block available to pass out.  	 * Read-only after initialization.  The first such byte starts at @@ -39,9 +46,25 @@ typedef struct _block {  */  struct _arena { +        /* 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; +  #if defined(Py_DEBUG)          /* Debug output */          size_t total_allocs; @@ -63,7 +86,8 @@ block_new(size_t size)  	b->ab_size = size;  	b->ab_mem = (void *)(b + 1);  	b->ab_next = NULL; -	b->ab_offset = 0; +	b->ab_offset = ROUNDUP((Py_uintptr_t)(b->ab_mem)) -  +	  (Py_uintptr_t)(b->ab_mem);  	return b;  } @@ -81,19 +105,20 @@ block_alloc(block *b, size_t size)  {  	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 *new = block_new( +		block *newbl = block_new(  				size < DEFAULT_BLOCK_SIZE ?  				DEFAULT_BLOCK_SIZE : size); -		if (!new) +		if (!newbl)  			return NULL;  		assert(!b->ab_next); -		b->ab_next = new; -		b = new; +		b->ab_next = newbl; +		b = newbl;  	}  	assert(b->ab_offset + size <= b->ab_size); @@ -134,6 +159,7 @@ PyArena_New()  void  PyArena_Free(PyArena *arena)  { +        int r;  	assert(arena);  #if defined(Py_DEBUG)          /* @@ -145,7 +171,17 @@ PyArena_Free(PyArena *arena)          */  #endif  	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);  }  | 
