Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Python source code "free_list = (PyIntObject *)Py_TYPE(v);" move the pointer free_list to next object?

Tags:

python

c

In python Source code, the int object creation method PyInt_FromLong, python create a new PyIntObject at the position of free_list's first element pointing to. Here is the code:

PyObject *
PyInt_FromLong(long ival)
{
    register PyIntObject *v;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
    if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
        v = small_ints[ival + NSMALLNEGINTS];
        Py_INCREF(v);
        return (PyObject *) v;
    }
#endif
    if (free_list == NULL) {
        if ((free_list = fill_free_list()) == NULL)
            return NULL;
    }
    /* Inline PyObject_New */
    v = free_list;
    free_list = (PyIntObject *)Py_TYPE(v);
    PyObject_INIT(v, &PyInt_Type);
    v->ob_ival = ival;
    return (PyObject *) v;
}

and Py_TYPE is:

#define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)

How does free_list = (PyIntObject *)Py_TYPE(v); work?

It move free_list to point to next object in list.

I think Py_TYPE(v) will return PyInt_Type, then (PyIntObject *)PyInt_Type won't be the next object.

like image 813
weidwonder Avatar asked Feb 19 '16 07:02

weidwonder


1 Answers

This behavior described in the comment on the top of the file:

free_list is a singly-linked list of available PyIntObjects, linked via abuse of their ob_type members.

You could also take a look into fill_free_list function, which allocates PyIntObjects according to the header comment:

static PyIntObject *
fill_free_list(void)
{
    PyIntObject *p, *q;
    /* Python's object allocator isn't appropriate for large blocks. */
    p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock));
    if (p == NULL)
        return (PyIntObject *) PyErr_NoMemory();
    ((PyIntBlock *)p)->next = block_list;
    block_list = (PyIntBlock *)p;
    /* Link the int objects together, from rear to front, then return
       the address of the last int object in the block. */
    p = &((PyIntBlock *)p)->objects[0];
    q = p + N_INTOBJECTS;
    while (--q > p)
        Py_TYPE(q) = (struct _typeobject *)(q-1);
    Py_TYPE(q) = NULL;
    return p + N_INTOBJECTS - 1;
}

The main line is Py_TYPE(q) = (struct _typeobject *)(q-1);

like image 200
awesoon Avatar answered Nov 12 '22 08:11

awesoon